summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfdd/bfd.c386
-rw-r--r--bfdd/bfd.h102
-rw-r--r--bfdd/bfdd_cli.c136
-rw-r--r--bfdd/bfdd_nb.c67
-rw-r--r--bfdd/bfdd_nb.h19
-rw-r--r--bfdd/bfdd_nb_config.c295
-rw-r--r--bfdd/ptm_adapter.c3
-rw-r--r--bgpd/bgp_evpn.c48
-rw-r--r--bgpd/bgp_filter.c10
-rw-r--r--bgpd/bgp_nexthop.c168
-rw-r--r--bgpd/bgp_nht.c80
-rw-r--r--bgpd/bgp_route.c26
-rw-r--r--bgpd/bgp_vty.c60
-rw-r--r--bgpd/bgp_zebra.c3
-rw-r--r--bgpd/bgpd.c4
-rwxr-xr-xconfigure.ac3
-rw-r--r--doc/developer/lists.rst37
-rw-r--r--doc/user/bfd.rst57
-rw-r--r--doc/user/bgp.rst39
-rw-r--r--doc/user/frr-reload.rst12
-rw-r--r--doc/user/index.rst1
-rw-r--r--doc/user/isisd.rst88
-rw-r--r--doc/user/ospf_fundamentals.rst6
-rw-r--r--doc/user/ospfd.rst12
-rw-r--r--doc/user/overview.rst7
-rw-r--r--doc/user/pim.rst10
-rw-r--r--doc/user/setup.rst3
-rw-r--r--doc/user/subdir.am1
-rw-r--r--doc/user/wecmp_linkbw.rst2
-rw-r--r--doc/user/zebra.rst40
-rw-r--r--include/linux/net_namespace.h1
-rw-r--r--isisd/isis_adjacency.c68
-rw-r--r--isisd/isis_adjacency.h8
-rw-r--r--isisd/isis_circuit.c2
-rw-r--r--isisd/isis_cli.c218
-rw-r--r--isisd/isis_errors.c6
-rw-r--r--isisd/isis_errors.h1
-rw-r--r--isisd/isis_lsp.c66
-rw-r--r--isisd/isis_main.c19
-rw-r--r--isisd/isis_misc.c20
-rw-r--r--isisd/isis_misc.h1
-rw-r--r--isisd/isis_nb.c132
-rw-r--r--isisd/isis_nb.h77
-rw-r--r--isisd/isis_nb_config.c283
-rw-r--r--isisd/isis_nb_state.c106
-rw-r--r--isisd/isis_route.c19
-rw-r--r--isisd/isis_route.h3
-rw-r--r--isisd/isis_spf.c2
-rw-r--r--isisd/isis_sr.c1970
-rw-r--r--isisd/isis_sr.h262
-rw-r--r--isisd/isis_tlvs.c88
-rw-r--r--isisd/isis_tlvs.h33
-rw-r--r--isisd/isis_zebra.c418
-rw-r--r--isisd/isis_zebra.h17
-rw-r--r--isisd/isisd.c44
-rw-r--r--isisd/isisd.h15
-rw-r--r--isisd/subdir.am3
-rw-r--r--ldpd/l2vpn.c12
-rw-r--r--ldpd/lde.c5
-rw-r--r--ldpd/ldp_vty_exec.c4
-rw-r--r--ldpd/ldpd.h9
-rw-r--r--ldpd/logmsg.c22
-rw-r--r--lib/command.c3
-rw-r--r--lib/command.h3
-rw-r--r--lib/if.c28
-rw-r--r--lib/if.h21
-rw-r--r--lib/mpls.h3
-rw-r--r--lib/netns_linux.c38
-rw-r--r--lib/northbound_grpc.cpp1307
-rw-r--r--lib/ns.h16
-rw-r--r--lib/prefix.c2
-rw-r--r--lib/prefix.h2
-rw-r--r--lib/typerb.c19
-rw-r--r--lib/typerb.h39
-rw-r--r--lib/typesafe.c17
-rw-r--r--lib/typesafe.h144
-rw-r--r--lib/vrf.c8
-rw-r--r--lib/vrf.h2
-rw-r--r--ospf6d/ospf6_asbr.c39
-rw-r--r--ospf6d/ospf6_lsdb.c15
-rw-r--r--ospf6d/ospf6_message.c44
-rw-r--r--ospf6d/ospf6_neighbor.c31
-rw-r--r--ospfd/ospf_asbr.c1
-rw-r--r--ospfd/ospf_asbr.h3
-rw-r--r--ospfd/ospf_vty.c10
-rw-r--r--ospfd/ospf_zebra.c11
-rw-r--r--pimd/pim_cmd.c111
-rw-r--r--pimd/pim_ifchannel.c7
-rw-r--r--ripd/rip_nb_state.c1
-rw-r--r--ripngd/ripng_nb_state.c1
-rw-r--r--tests/lib/test_typelist.h25
-rw-r--r--tests/topotests/all-protocol-startup/r1/babeld.conf4
-rw-r--r--tests/topotests/all-protocol-startup/r1/nhrpd.conf1
-rwxr-xr-xtests/topotests/all-protocol-startup/test_all_protocol_startup.py2
-rwxr-xr-xtests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py2
-rwxr-xr-xtests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py2
-rw-r--r--tests/topotests/bgp_gr_functionality_topo1/bgp_gr_topojson_topo1.json115
-rwxr-xr-xtests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py3495
-rw-r--r--tests/topotests/bgp_gr_functionality_topo2/bgp_gr_topojson_topo2.json334
-rwxr-xr-xtests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py3085
-rw-r--r--tests/topotests/bgp_multi_vrf_topo1/bgp_multi_vrf_topo1.json884
-rwxr-xr-xtests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py6300
-rw-r--r--tests/topotests/bgp_multi_vrf_topo2/bgp_multi_vrf_topo2.json1277
-rwxr-xr-xtests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py2012
-rwxr-xr-xtests/topotests/conftest.py2
-rw-r--r--tests/topotests/isis-sr-topo1/__init__.py0
-rw-r--r--tests/topotests/isis-sr-topo1/rt1/isisd.conf30
-rw-r--r--tests/topotests/isis-sr-topo1/rt1/step1/show_ip_route.ref294
-rw-r--r--tests/topotests/isis-sr-topo1/rt1/step1/show_ipv6_route.ref121
-rw-r--r--tests/topotests/isis-sr-topo1/rt1/step1/show_mpls_table.ref134
-rw-r--r--tests/topotests/isis-sr-topo1/rt1/step1/show_yang_interface_isis_adjacencies.ref34
-rw-r--r--tests/topotests/isis-sr-topo1/rt1/step10/show_ip_route.ref287
-rw-r--r--tests/topotests/isis-sr-topo1/rt1/step10/show_ipv6_route.ref121
-rw-r--r--tests/topotests/isis-sr-topo1/rt1/step10/show_mpls_table.ref156
l---------tests/topotests/isis-sr-topo1/rt1/step10/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt1/step2/show_ip_route.ref287
-rw-r--r--tests/topotests/isis-sr-topo1/rt1/step2/show_ipv6_route.ref121
-rw-r--r--tests/topotests/isis-sr-topo1/rt1/step2/show_mpls_table.ref134
l---------tests/topotests/isis-sr-topo1/rt1/step2/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt1/step3/show_ip_route.ref254
-rw-r--r--tests/topotests/isis-sr-topo1/rt1/step3/show_ipv6_route.ref90
-rw-r--r--tests/topotests/isis-sr-topo1/rt1/step3/show_mpls_table.ref98
l---------tests/topotests/isis-sr-topo1/rt1/step3/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt1/step4/show_ip_route.ref287
-rw-r--r--tests/topotests/isis-sr-topo1/rt1/step4/show_ipv6_route.ref121
-rw-r--r--tests/topotests/isis-sr-topo1/rt1/step4/show_mpls_table.ref134
l---------tests/topotests/isis-sr-topo1/rt1/step4/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt1/step5/show_ip_route.ref281
-rw-r--r--tests/topotests/isis-sr-topo1/rt1/step5/show_ipv6_route.ref115
-rw-r--r--tests/topotests/isis-sr-topo1/rt1/step5/show_mpls_table.ref98
l---------tests/topotests/isis-sr-topo1/rt1/step5/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt1/step6/show_ip_route.ref287
-rw-r--r--tests/topotests/isis-sr-topo1/rt1/step6/show_ipv6_route.ref121
-rw-r--r--tests/topotests/isis-sr-topo1/rt1/step6/show_mpls_table.ref134
l---------tests/topotests/isis-sr-topo1/rt1/step6/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt1/step7/show_ip_route.ref287
-rw-r--r--tests/topotests/isis-sr-topo1/rt1/step7/show_ipv6_route.ref121
-rw-r--r--tests/topotests/isis-sr-topo1/rt1/step7/show_mpls_table.ref134
l---------tests/topotests/isis-sr-topo1/rt1/step7/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt1/step8/show_ip_route.ref287
-rw-r--r--tests/topotests/isis-sr-topo1/rt1/step8/show_ipv6_route.ref121
-rw-r--r--tests/topotests/isis-sr-topo1/rt1/step8/show_mpls_table.ref134
l---------tests/topotests/isis-sr-topo1/rt1/step8/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt1/step9/show_ip_route.ref287
-rw-r--r--tests/topotests/isis-sr-topo1/rt1/step9/show_ipv6_route.ref121
-rw-r--r--tests/topotests/isis-sr-topo1/rt1/step9/show_mpls_table.ref156
l---------tests/topotests/isis-sr-topo1/rt1/step9/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt1/zebra.conf19
-rw-r--r--tests/topotests/isis-sr-topo1/rt2/isisd.conf41
-rw-r--r--tests/topotests/isis-sr-topo1/rt2/step1/show_ip_route.ref347
-rw-r--r--tests/topotests/isis-sr-topo1/rt2/step1/show_ipv6_route.ref148
-rw-r--r--tests/topotests/isis-sr-topo1/rt2/step1/show_mpls_table.ref192
-rw-r--r--tests/topotests/isis-sr-topo1/rt2/step1/show_yang_interface_isis_adjacencies.ref74
-rw-r--r--tests/topotests/isis-sr-topo1/rt2/step10/show_ip_route.ref259
-rw-r--r--tests/topotests/isis-sr-topo1/rt2/step10/show_ipv6_route.ref130
-rw-r--r--tests/topotests/isis-sr-topo1/rt2/step10/show_mpls_table.ref156
l---------tests/topotests/isis-sr-topo1/rt2/step10/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt2/step2/show_ip_route.ref320
-rw-r--r--tests/topotests/isis-sr-topo1/rt2/step2/show_ipv6_route.ref130
-rw-r--r--tests/topotests/isis-sr-topo1/rt2/step2/show_mpls_table.ref168
l---------tests/topotests/isis-sr-topo1/rt2/step2/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt2/step3/show_ip_route.ref273
-rw-r--r--tests/topotests/isis-sr-topo1/rt2/step3/show_ipv6_route.ref99
-rw-r--r--tests/topotests/isis-sr-topo1/rt2/step3/show_mpls_table.ref132
l---------tests/topotests/isis-sr-topo1/rt2/step3/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt2/step4/show_ip_route.ref320
-rw-r--r--tests/topotests/isis-sr-topo1/rt2/step4/show_ipv6_route.ref130
-rw-r--r--tests/topotests/isis-sr-topo1/rt2/step4/show_mpls_table.ref168
l---------tests/topotests/isis-sr-topo1/rt2/step4/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt2/step5/show_ip_route.ref314
-rw-r--r--tests/topotests/isis-sr-topo1/rt2/step5/show_ipv6_route.ref124
-rw-r--r--tests/topotests/isis-sr-topo1/rt2/step5/show_mpls_table.ref132
l---------tests/topotests/isis-sr-topo1/rt2/step5/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt2/step6/show_ip_route.ref320
-rw-r--r--tests/topotests/isis-sr-topo1/rt2/step6/show_ipv6_route.ref130
-rw-r--r--tests/topotests/isis-sr-topo1/rt2/step6/show_mpls_table.ref168
l---------tests/topotests/isis-sr-topo1/rt2/step6/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt2/step7/show_ip_route.ref317
-rw-r--r--tests/topotests/isis-sr-topo1/rt2/step7/show_ipv6_route.ref127
-rw-r--r--tests/topotests/isis-sr-topo1/rt2/step7/show_mpls_table.ref144
l---------tests/topotests/isis-sr-topo1/rt2/step7/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt2/step8/show_ip_route.ref320
-rw-r--r--tests/topotests/isis-sr-topo1/rt2/step8/show_ipv6_route.ref130
-rw-r--r--tests/topotests/isis-sr-topo1/rt2/step8/show_mpls_table.ref168
l---------tests/topotests/isis-sr-topo1/rt2/step8/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt2/step9/show_ip_route.ref320
-rw-r--r--tests/topotests/isis-sr-topo1/rt2/step9/show_ipv6_route.ref130
-rw-r--r--tests/topotests/isis-sr-topo1/rt2/step9/show_mpls_table.ref168
l---------tests/topotests/isis-sr-topo1/rt2/step9/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt2/zebra.conf25
-rw-r--r--tests/topotests/isis-sr-topo1/rt3/isisd.conf41
-rw-r--r--tests/topotests/isis-sr-topo1/rt3/step1/show_ip_route.ref347
-rw-r--r--tests/topotests/isis-sr-topo1/rt3/step1/show_ipv6_route.ref148
-rw-r--r--tests/topotests/isis-sr-topo1/rt3/step1/show_mpls_table.ref192
-rw-r--r--tests/topotests/isis-sr-topo1/rt3/step1/show_yang_interface_isis_adjacencies.ref74
-rw-r--r--tests/topotests/isis-sr-topo1/rt3/step10/show_ip_route.ref327
-rw-r--r--tests/topotests/isis-sr-topo1/rt3/step10/show_ipv6_route.ref130
-rw-r--r--tests/topotests/isis-sr-topo1/rt3/step10/show_mpls_table.ref168
l---------tests/topotests/isis-sr-topo1/rt3/step10/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt3/step2/show_ip_route.ref327
-rw-r--r--tests/topotests/isis-sr-topo1/rt3/step2/show_ipv6_route.ref130
-rw-r--r--tests/topotests/isis-sr-topo1/rt3/step2/show_mpls_table.ref168
l---------tests/topotests/isis-sr-topo1/rt3/step2/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt3/step3/show_ip_route.ref280
-rw-r--r--tests/topotests/isis-sr-topo1/rt3/step3/show_ipv6_route.ref99
-rw-r--r--tests/topotests/isis-sr-topo1/rt3/step3/show_mpls_table.ref132
l---------tests/topotests/isis-sr-topo1/rt3/step3/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt3/step4/show_ip_route.ref327
-rw-r--r--tests/topotests/isis-sr-topo1/rt3/step4/show_ipv6_route.ref130
-rw-r--r--tests/topotests/isis-sr-topo1/rt3/step4/show_mpls_table.ref168
l---------tests/topotests/isis-sr-topo1/rt3/step4/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt3/step5/show_ip_route.ref321
-rw-r--r--tests/topotests/isis-sr-topo1/rt3/step5/show_ipv6_route.ref124
-rw-r--r--tests/topotests/isis-sr-topo1/rt3/step5/show_mpls_table.ref132
l---------tests/topotests/isis-sr-topo1/rt3/step5/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt3/step6/show_ip_route.ref327
-rw-r--r--tests/topotests/isis-sr-topo1/rt3/step6/show_ipv6_route.ref130
-rw-r--r--tests/topotests/isis-sr-topo1/rt3/step6/show_mpls_table.ref168
l---------tests/topotests/isis-sr-topo1/rt3/step6/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt3/step7/show_ip_route.ref324
-rw-r--r--tests/topotests/isis-sr-topo1/rt3/step7/show_ipv6_route.ref127
-rw-r--r--tests/topotests/isis-sr-topo1/rt3/step7/show_mpls_table.ref144
l---------tests/topotests/isis-sr-topo1/rt3/step7/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt3/step8/show_ip_route.ref327
-rw-r--r--tests/topotests/isis-sr-topo1/rt3/step8/show_ipv6_route.ref130
-rw-r--r--tests/topotests/isis-sr-topo1/rt3/step8/show_mpls_table.ref168
l---------tests/topotests/isis-sr-topo1/rt3/step8/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt3/step9/show_ip_route.ref327
-rw-r--r--tests/topotests/isis-sr-topo1/rt3/step9/show_ipv6_route.ref130
-rw-r--r--tests/topotests/isis-sr-topo1/rt3/step9/show_mpls_table.ref168
l---------tests/topotests/isis-sr-topo1/rt3/step9/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt3/zebra.conf25
-rw-r--r--tests/topotests/isis-sr-topo1/rt4/isisd.conf48
-rw-r--r--tests/topotests/isis-sr-topo1/rt4/step1/show_ip_route.ref323
-rw-r--r--tests/topotests/isis-sr-topo1/rt4/step1/show_ipv6_route.ref148
-rw-r--r--tests/topotests/isis-sr-topo1/rt4/step1/show_mpls_table.ref192
-rw-r--r--tests/topotests/isis-sr-topo1/rt4/step1/show_yang_interface_isis_adjacencies.ref86
-rw-r--r--tests/topotests/isis-sr-topo1/rt4/step10/show_ip_route.ref277
-rw-r--r--tests/topotests/isis-sr-topo1/rt4/step10/show_ipv6_route.ref139
-rw-r--r--tests/topotests/isis-sr-topo1/rt4/step10/show_mpls_table.ref162
l---------tests/topotests/isis-sr-topo1/rt4/step10/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt4/step2/show_ip_route.ref335
-rw-r--r--tests/topotests/isis-sr-topo1/rt4/step2/show_ipv6_route.ref139
-rw-r--r--tests/topotests/isis-sr-topo1/rt4/step2/show_mpls_table.ref180
-rw-r--r--tests/topotests/isis-sr-topo1/rt4/step2/show_yang_interface_isis_adjacencies.ref66
-rw-r--r--tests/topotests/isis-sr-topo1/rt4/step3/show_ip_route.ref306
-rw-r--r--tests/topotests/isis-sr-topo1/rt4/step3/show_ipv6_route.ref126
-rw-r--r--tests/topotests/isis-sr-topo1/rt4/step3/show_mpls_table.ref168
-rw-r--r--tests/topotests/isis-sr-topo1/rt4/step3/show_yang_interface_isis_adjacencies.ref46
-rw-r--r--tests/topotests/isis-sr-topo1/rt4/step4/show_ip_route.ref335
-rw-r--r--tests/topotests/isis-sr-topo1/rt4/step4/show_ipv6_route.ref139
-rw-r--r--tests/topotests/isis-sr-topo1/rt4/step4/show_mpls_table.ref180
l---------tests/topotests/isis-sr-topo1/rt4/step4/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt4/step5/show_ip_route.ref329
-rw-r--r--tests/topotests/isis-sr-topo1/rt4/step5/show_ipv6_route.ref133
-rw-r--r--tests/topotests/isis-sr-topo1/rt4/step5/show_mpls_table.ref132
l---------tests/topotests/isis-sr-topo1/rt4/step5/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt4/step6/show_ip_route.ref335
-rw-r--r--tests/topotests/isis-sr-topo1/rt4/step6/show_ipv6_route.ref139
-rw-r--r--tests/topotests/isis-sr-topo1/rt4/step6/show_mpls_table.ref180
l---------tests/topotests/isis-sr-topo1/rt4/step6/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt4/step7/show_ip_route.ref329
-rw-r--r--tests/topotests/isis-sr-topo1/rt4/step7/show_ipv6_route.ref133
-rw-r--r--tests/topotests/isis-sr-topo1/rt4/step7/show_mpls_table.ref144
l---------tests/topotests/isis-sr-topo1/rt4/step7/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt4/step8/show_ip_route.ref335
-rw-r--r--tests/topotests/isis-sr-topo1/rt4/step8/show_ipv6_route.ref139
-rw-r--r--tests/topotests/isis-sr-topo1/rt4/step8/show_mpls_table.ref180
l---------tests/topotests/isis-sr-topo1/rt4/step8/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt4/step9/show_ip_route.ref335
-rw-r--r--tests/topotests/isis-sr-topo1/rt4/step9/show_ipv6_route.ref139
-rw-r--r--tests/topotests/isis-sr-topo1/rt4/step9/show_mpls_table.ref180
l---------tests/topotests/isis-sr-topo1/rt4/step9/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt4/zebra.conf28
-rw-r--r--tests/topotests/isis-sr-topo1/rt5/isisd.conf48
-rw-r--r--tests/topotests/isis-sr-topo1/rt5/step1/show_ip_route.ref323
-rw-r--r--tests/topotests/isis-sr-topo1/rt5/step1/show_ipv6_route.ref148
-rw-r--r--tests/topotests/isis-sr-topo1/rt5/step1/show_mpls_table.ref192
-rw-r--r--tests/topotests/isis-sr-topo1/rt5/step1/show_yang_interface_isis_adjacencies.ref86
-rw-r--r--tests/topotests/isis-sr-topo1/rt5/step10/show_ip_route.ref312
-rw-r--r--tests/topotests/isis-sr-topo1/rt5/step10/show_ipv6_route.ref139
-rw-r--r--tests/topotests/isis-sr-topo1/rt5/step10/show_mpls_table.ref180
l---------tests/topotests/isis-sr-topo1/rt5/step10/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt5/step2/show_ip_route.ref319
-rw-r--r--tests/topotests/isis-sr-topo1/rt5/step2/show_ipv6_route.ref139
-rw-r--r--tests/topotests/isis-sr-topo1/rt5/step2/show_mpls_table.ref180
-rw-r--r--tests/topotests/isis-sr-topo1/rt5/step2/show_yang_interface_isis_adjacencies.ref66
-rw-r--r--tests/topotests/isis-sr-topo1/rt5/step3/show_ip_route.ref284
-rw-r--r--tests/topotests/isis-sr-topo1/rt5/step3/show_ipv6_route.ref126
-rw-r--r--tests/topotests/isis-sr-topo1/rt5/step3/show_mpls_table.ref168
-rw-r--r--tests/topotests/isis-sr-topo1/rt5/step3/show_yang_interface_isis_adjacencies.ref46
-rw-r--r--tests/topotests/isis-sr-topo1/rt5/step4/show_ip_route.ref319
-rw-r--r--tests/topotests/isis-sr-topo1/rt5/step4/show_ipv6_route.ref139
-rw-r--r--tests/topotests/isis-sr-topo1/rt5/step4/show_mpls_table.ref180
-rw-r--r--tests/topotests/isis-sr-topo1/rt5/step4/show_yang_interface_isis_adjacencies.ref66
-rw-r--r--tests/topotests/isis-sr-topo1/rt5/step5/show_ip_route.ref313
-rw-r--r--tests/topotests/isis-sr-topo1/rt5/step5/show_ipv6_route.ref133
-rw-r--r--tests/topotests/isis-sr-topo1/rt5/step5/show_mpls_table.ref132
l---------tests/topotests/isis-sr-topo1/rt5/step5/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt5/step6/show_ip_route.ref319
-rw-r--r--tests/topotests/isis-sr-topo1/rt5/step6/show_ipv6_route.ref139
-rw-r--r--tests/topotests/isis-sr-topo1/rt5/step6/show_mpls_table.ref180
l---------tests/topotests/isis-sr-topo1/rt5/step6/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt5/step7/show_ip_route.ref313
-rw-r--r--tests/topotests/isis-sr-topo1/rt5/step7/show_ipv6_route.ref133
-rw-r--r--tests/topotests/isis-sr-topo1/rt5/step7/show_mpls_table.ref144
l---------tests/topotests/isis-sr-topo1/rt5/step7/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt5/step8/show_ip_route.ref319
-rw-r--r--tests/topotests/isis-sr-topo1/rt5/step8/show_ipv6_route.ref139
-rw-r--r--tests/topotests/isis-sr-topo1/rt5/step8/show_mpls_table.ref180
l---------tests/topotests/isis-sr-topo1/rt5/step8/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt5/step9/show_ip_route.ref319
-rw-r--r--tests/topotests/isis-sr-topo1/rt5/step9/show_ipv6_route.ref139
-rw-r--r--tests/topotests/isis-sr-topo1/rt5/step9/show_mpls_table.ref180
l---------tests/topotests/isis-sr-topo1/rt5/step9/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt5/zebra.conf28
-rw-r--r--tests/topotests/isis-sr-topo1/rt6/isisd.conf36
-rw-r--r--tests/topotests/isis-sr-topo1/rt6/step1/show_ip_route.ref291
-rw-r--r--tests/topotests/isis-sr-topo1/rt6/step1/show_ipv6_route.ref121
-rw-r--r--tests/topotests/isis-sr-topo1/rt6/step1/show_mpls_table.ref134
-rw-r--r--tests/topotests/isis-sr-topo1/rt6/step1/show_yang_interface_isis_adjacencies.ref46
-rw-r--r--tests/topotests/isis-sr-topo1/rt6/step10/show_ip_route.ref284
-rw-r--r--tests/topotests/isis-sr-topo1/rt6/step10/show_ipv6_route.ref121
-rw-r--r--tests/topotests/isis-sr-topo1/rt6/step10/show_mpls_table.ref134
l---------tests/topotests/isis-sr-topo1/rt6/step10/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt6/step2/show_ip_route.ref284
-rw-r--r--tests/topotests/isis-sr-topo1/rt6/step2/show_ipv6_route.ref121
-rw-r--r--tests/topotests/isis-sr-topo1/rt6/step2/show_mpls_table.ref134
l---------tests/topotests/isis-sr-topo1/rt6/step2/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt6/step3/show_ip_route.ref2
-rw-r--r--tests/topotests/isis-sr-topo1/rt6/step3/show_ipv6_route.ref2
-rw-r--r--tests/topotests/isis-sr-topo1/rt6/step3/show_mpls_table.ref2
-rw-r--r--tests/topotests/isis-sr-topo1/rt6/step3/show_yang_interface_isis_adjacencies.ref3
-rw-r--r--tests/topotests/isis-sr-topo1/rt6/step4/show_ip_route.ref284
-rw-r--r--tests/topotests/isis-sr-topo1/rt6/step4/show_ipv6_route.ref121
-rw-r--r--tests/topotests/isis-sr-topo1/rt6/step4/show_mpls_table.ref134
l---------tests/topotests/isis-sr-topo1/rt6/step4/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt6/step5/show_ip_route.ref266
-rw-r--r--tests/topotests/isis-sr-topo1/rt6/step5/show_ipv6_route.ref103
-rw-r--r--tests/topotests/isis-sr-topo1/rt6/step5/show_mpls_table.ref2
l---------tests/topotests/isis-sr-topo1/rt6/step5/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt6/step6/show_ip_route.ref284
-rw-r--r--tests/topotests/isis-sr-topo1/rt6/step6/show_ipv6_route.ref121
-rw-r--r--tests/topotests/isis-sr-topo1/rt6/step6/show_mpls_table.ref134
l---------tests/topotests/isis-sr-topo1/rt6/step6/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt6/step7/show_ip_route.ref278
-rw-r--r--tests/topotests/isis-sr-topo1/rt6/step7/show_ipv6_route.ref115
-rw-r--r--tests/topotests/isis-sr-topo1/rt6/step7/show_mpls_table.ref98
l---------tests/topotests/isis-sr-topo1/rt6/step7/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt6/step8/show_ip_route.ref284
-rw-r--r--tests/topotests/isis-sr-topo1/rt6/step8/show_ipv6_route.ref121
-rw-r--r--tests/topotests/isis-sr-topo1/rt6/step8/show_mpls_table.ref134
l---------tests/topotests/isis-sr-topo1/rt6/step8/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt6/step9/show_ip_route.ref284
-rw-r--r--tests/topotests/isis-sr-topo1/rt6/step9/show_ipv6_route.ref121
-rw-r--r--tests/topotests/isis-sr-topo1/rt6/step9/show_mpls_table.ref134
l---------tests/topotests/isis-sr-topo1/rt6/step9/show_yang_interface_isis_adjacencies.ref1
-rw-r--r--tests/topotests/isis-sr-topo1/rt6/zebra.conf22
-rwxr-xr-xtests/topotests/isis-sr-topo1/test_isis_sr_topo1.py915
-rw-r--r--tests/topotests/lib/bgp.py1978
-rw-r--r--tests/topotests/lib/common_config.py1076
-rwxr-xr-xtests/topotests/lib/test/test_json.py211
-rw-r--r--tests/topotests/lib/topogen.py34
-rw-r--r--tests/topotests/lib/topojson.py3
-rw-r--r--tests/topotests/lib/topotest.py430
-rwxr-xr-xtools/frr-reload.py19
-rwxr-xr-xtools/frr.in2
-rw-r--r--tools/frrcommon.sh.in6
-rw-r--r--vtysh/vtysh.c21
-rw-r--r--yang/LICENSE22
-rw-r--r--yang/frr-bfdd.yang67
-rw-r--r--yang/frr-eigrpd.yang27
-rw-r--r--yang/frr-filter.yang28
-rw-r--r--yang/frr-igmp.yang27
-rw-r--r--yang/frr-interface.yang27
-rw-r--r--yang/frr-isisd.yang138
-rw-r--r--yang/frr-module-translator.yang27
-rw-r--r--yang/frr-nexthop.yang27
-rw-r--r--yang/frr-pim-rp.yang27
-rw-r--r--yang/frr-pim.yang27
-rw-r--r--yang/frr-ripd.yang27
-rw-r--r--yang/frr-ripngd.yang27
-rw-r--r--yang/frr-route-map.yang28
-rw-r--r--yang/frr-route-types.yang27
-rw-r--r--yang/frr-routing.yang27
-rw-r--r--yang/frr-staticd.yang27
-rw-r--r--yang/frr-test-module.yang28
-rw-r--r--yang/frr-vrf.yang27
-rw-r--r--yang/frr-vrrpd.yang27
-rw-r--r--yang/frr-zebra.yang64
-rw-r--r--zebra/dplane_fpm_nl.c214
-rw-r--r--zebra/if_netlink.c50
-rw-r--r--zebra/interface.c31
-rw-r--r--zebra/main.c4
-rw-r--r--zebra/rib.h42
-rw-r--r--zebra/rt_netlink.c104
-rw-r--r--zebra/rt_netlink.h7
-rw-r--r--zebra/rtadv.c38
-rw-r--r--zebra/rtadv.h4
-rw-r--r--zebra/zapi_msg.c17
-rw-r--r--zebra/zebra_dplane.c7
-rw-r--r--zebra/zebra_dplane.h4
-rw-r--r--zebra/zebra_fpm.c80
-rw-r--r--zebra/zebra_fpm_netlink.c33
-rw-r--r--zebra/zebra_gr.c6
-rw-r--r--zebra/zebra_l2.c34
-rw-r--r--zebra/zebra_l2.h11
-rw-r--r--zebra/zebra_mpls.h7
-rw-r--r--zebra/zebra_nb.c202
-rw-r--r--zebra/zebra_nb.h179
-rw-r--r--zebra/zebra_nb_config.c50
-rw-r--r--zebra/zebra_nb_state.c666
-rw-r--r--zebra/zebra_netns_id.c43
-rw-r--r--zebra/zebra_netns_id.h2
-rw-r--r--zebra/zebra_netns_notify.c19
-rw-r--r--zebra/zebra_nhg.c59
-rw-r--r--zebra/zebra_nhg.h4
-rw-r--r--zebra/zebra_ns.c17
-rw-r--r--zebra/zebra_ns.h9
-rw-r--r--zebra/zebra_pw.c152
-rw-r--r--zebra/zebra_rib.c44
-rw-r--r--zebra/zebra_rnh.c31
-rw-r--r--zebra/zebra_rnh.h14
-rw-r--r--zebra/zebra_router.c20
-rw-r--r--zebra/zebra_router.h3
-rw-r--r--zebra/zebra_vrf.h6
-rw-r--r--zebra/zebra_vty.c20
-rw-r--r--zebra/zebra_vxlan.c427
-rw-r--r--zebra/zebra_vxlan_private.h1
-rw-r--r--zebra/zserv.h2
430 files changed, 66424 insertions, 2560 deletions
diff --git a/bfdd/bfd.c b/bfdd/bfd.c
index f9e572db4d..a021b5cabc 100644
--- a/bfdd/bfd.c
+++ b/bfdd/bfd.c
@@ -33,6 +33,7 @@
#include "bfd.h"
DEFINE_MTYPE_STATIC(BFDD, BFDD_CONFIG, "long-lived configuration memory")
+DEFINE_MTYPE_STATIC(BFDD, BFDD_PROFILE, "long-lived profile memory")
DEFINE_MTYPE_STATIC(BFDD, BFDD_SESSION_OBSERVER, "Session observer")
DEFINE_MTYPE_STATIC(BFDD, BFDD_VRF, "BFD VRF")
@@ -53,12 +54,186 @@ static void bs_up_handler(struct bfd_session *bs, int nstate);
static void bs_neighbour_admin_down_handler(struct bfd_session *bfd,
uint8_t diag);
+/**
+ * Remove BFD profile from all BFD sessions so we don't leave dangling
+ * pointers.
+ */
+static void bfd_profile_detach(struct bfd_profile *bp);
+
/* Zeroed array with the size of an IPv6 address. */
struct in6_addr zero_addr;
+/** BFD profiles list. */
+struct bfdproflist bplist;
+
/*
* Functions
*/
+struct bfd_profile *bfd_profile_lookup(const char *name)
+{
+ struct bfd_profile *bp;
+
+ TAILQ_FOREACH (bp, &bplist, entry) {
+ if (strcmp(name, bp->name))
+ continue;
+
+ return bp;
+ }
+
+ return NULL;
+}
+
+static void bfd_profile_set_default(struct bfd_profile *bp)
+{
+ bp->admin_shutdown = true;
+ bp->detection_multiplier = BFD_DEFDETECTMULT;
+ bp->echo_mode = false;
+ bp->min_echo_rx = BFD_DEF_REQ_MIN_ECHO;
+ bp->min_rx = BFD_DEFREQUIREDMINRX;
+ bp->min_tx = BFD_DEFDESIREDMINTX;
+}
+
+struct bfd_profile *bfd_profile_new(const char *name)
+{
+ struct bfd_profile *bp;
+
+ /* Search for duplicates. */
+ if (bfd_profile_lookup(name) != NULL)
+ return NULL;
+
+ /* Allocate, name it and put into list. */
+ bp = XCALLOC(MTYPE_BFDD_PROFILE, sizeof(*bp));
+ strlcpy(bp->name, name, sizeof(bp->name));
+ TAILQ_INSERT_TAIL(&bplist, bp, entry);
+
+ /* Set default values. */
+ bfd_profile_set_default(bp);
+
+ return bp;
+}
+
+void bfd_profile_free(struct bfd_profile *bp)
+{
+ /* Detach from any session. */
+ bfd_profile_detach(bp);
+
+ /* Remove from global list. */
+ TAILQ_REMOVE(&bplist, bp, entry);
+ free(bp);
+}
+
+/**
+ * Removes a profile and tests whether it needs to apply the changes or not.
+ *
+ * \param bs the BFD session.
+ * \param apply whether or not to apply configurations immediately.
+ */
+static void _bfd_profile_remove(struct bfd_session *bs, bool apply)
+{
+ struct bfd_profile *bp;
+
+ /* No profile applied, nothing to do. */
+ bp = bs->profile;
+ if (bp == NULL)
+ return;
+
+ /* Remove the profile association. */
+ bs->profile = NULL;
+
+ /* Set multiplier to the default. */
+ bs->detect_mult = bs->peer_profile.detection_multiplier;
+
+ /* Set timers back to user configuration. */
+ bs->timers.desired_min_tx = bs->peer_profile.min_tx;
+ bs->timers.required_min_rx = bs->peer_profile.min_rx;
+
+ /* We can only apply echo options on single hop sessions. */
+ if (!CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
+ /* Set default echo timer. */
+ bs->timers.required_min_echo = bs->peer_profile.min_echo_rx;
+
+ /* Default is no echo mode. */
+ if (apply)
+ bfd_set_echo(bs, bs->peer_profile.echo_mode);
+ }
+
+ if (apply)
+ bfd_set_shutdown(bs, bs->peer_profile.admin_shutdown);
+}
+
+void bfd_profile_apply(const char *profname, struct bfd_session *bs)
+{
+ struct bfd_profile *bp;
+
+ /* Remove previous profile if any. */
+ if (bs->profile_name) {
+ _bfd_profile_remove(bs, false);
+
+ /* We are changing profiles. */
+ if (strcmp(bs->profile_name, profname)) {
+ XFREE(MTYPE_BFDD_PROFILE, bs->profile_name);
+ bs->profile_name =
+ XSTRDUP(MTYPE_BFDD_PROFILE, profname);
+ }
+ } else /* Save the current profile name (in case it doesn't exist). */
+ bs->profile_name = XSTRDUP(MTYPE_BFDD_PROFILE, profname);
+
+ /* Look up new profile to apply. */
+ bp = bfd_profile_lookup(profname);
+ if (bp == NULL)
+ return;
+
+ /* Point to profile if it exists. */
+ bs->profile = bp;
+
+ /* Set multiplier if not the default. */
+ if (bs->peer_profile.detection_multiplier == BFD_DEFDETECTMULT)
+ bs->detect_mult = bp->detection_multiplier;
+ else
+ bs->detect_mult = bs->peer_profile.detection_multiplier;
+
+ /* Set timers if not the default. */
+ if (bs->peer_profile.min_tx == BFD_DEFDESIREDMINTX)
+ bs->timers.desired_min_tx = bp->min_tx;
+ else
+ bs->timers.desired_min_tx = bs->peer_profile.min_tx;
+
+ if (bs->peer_profile.min_rx == BFD_DEFREQUIREDMINRX)
+ bs->timers.required_min_rx = bp->min_rx;
+ else
+ bs->timers.required_min_rx = bs->peer_profile.min_rx;
+
+ /* We can only apply echo options on single hop sessions. */
+ if (!CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) {
+ /* Configure remote echo if it was default. */
+ if (bs->peer_profile.min_echo_rx == BFD_DEF_REQ_MIN_ECHO)
+ bs->timers.required_min_echo = bp->min_echo_rx;
+ else
+ bs->timers.required_min_echo =
+ bs->peer_profile.min_echo_rx;
+
+ /* Toggle echo if default value. */
+ if (bs->peer_profile.echo_mode == false)
+ bfd_set_echo(bs, bp->echo_mode);
+ else
+ bfd_set_echo(bs, bs->peer_profile.echo_mode);
+ }
+
+ /* Toggle 'no shutdown' if default value. */
+ if (bs->peer_profile.admin_shutdown)
+ bfd_set_shutdown(bs, bp->admin_shutdown);
+ else
+ bfd_set_shutdown(bs, bs->peer_profile.admin_shutdown);
+}
+
+void bfd_profile_remove(struct bfd_session *bs)
+{
+ /* Remove any previous set profile name. */
+ XFREE(MTYPE_BFDD_PROFILE, bs->profile_name);
+
+ _bfd_profile_remove(bs, true);
+}
+
void gen_bfd_key(struct bfd_key *key, struct sockaddr_any *peer,
struct sockaddr_any *local, bool mhop, const char *ifname,
const char *vrfname)
@@ -494,6 +669,9 @@ struct bfd_session *bfd_session_new(void)
bs = XCALLOC(MTYPE_BFDD_CONFIG, sizeof(*bs));
+ /* Set peer session defaults. */
+ bfd_profile_set_default(&bs->peer_profile);
+
bs->timers.desired_min_tx = BFD_DEFDESIREDMINTX;
bs->timers.required_min_rx = BFD_DEFREQUIREDMINRX;
bs->timers.required_min_echo = BFD_DEF_REQ_MIN_ECHO;
@@ -550,86 +728,43 @@ int bfd_session_update_label(struct bfd_session *bs, const char *nlabel)
static void _bfd_session_update(struct bfd_session *bs,
struct bfd_peer_cfg *bpc)
{
- if (bpc->bpc_echo) {
- /* Check if echo mode is already active. */
- if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
- goto skip_echo;
-
- SET_FLAG(bs->flags, BFD_SESS_FLAG_ECHO);
-
- /* Activate/update echo receive timeout timer. */
- bs_echo_timer_handler(bs);
- } else {
- /* Check if echo mode is already disabled. */
- if (!CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
- goto skip_echo;
-
- UNSET_FLAG(bs->flags, BFD_SESS_FLAG_ECHO);
- ptm_bfd_echo_stop(bs);
- }
-
-skip_echo:
- if (bpc->bpc_has_txinterval)
+ if (bpc->bpc_has_txinterval) {
bs->timers.desired_min_tx = bpc->bpc_txinterval * 1000;
+ bs->peer_profile.min_tx = bs->timers.desired_min_tx;
+ }
- if (bpc->bpc_has_recvinterval)
+ if (bpc->bpc_has_recvinterval) {
bs->timers.required_min_rx = bpc->bpc_recvinterval * 1000;
+ bs->peer_profile.min_rx = bs->timers.required_min_rx;
+ }
- if (bpc->bpc_has_detectmultiplier)
+ if (bpc->bpc_has_detectmultiplier) {
bs->detect_mult = bpc->bpc_detectmultiplier;
+ bs->peer_profile.detection_multiplier = bs->detect_mult;
+ }
- if (bpc->bpc_has_echointerval)
+ if (bpc->bpc_has_echointerval) {
bs->timers.required_min_echo = bpc->bpc_echointerval * 1000;
+ bs->peer_profile.min_echo_rx = bs->timers.required_min_echo;
+ }
if (bpc->bpc_has_label)
bfd_session_update_label(bs, bpc->bpc_label);
- if (bpc->bpc_shutdown) {
- /* Check if already shutdown. */
- if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
- return;
-
- SET_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN);
-
- /* Disable all events. */
- bfd_recvtimer_delete(bs);
- bfd_echo_recvtimer_delete(bs);
- bfd_xmttimer_delete(bs);
- bfd_echo_xmttimer_delete(bs);
-
- /* Change and notify state change. */
- bs->ses_state = PTM_BFD_ADM_DOWN;
- control_notify(bs, bs->ses_state);
-
- /* Don't try to send packets with a disabled session. */
- if (bs->sock != -1)
- ptm_bfd_snd(bs, 0);
- } else {
- /* Check if already working. */
- if (!CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
- return;
-
- UNSET_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN);
-
- /* Change and notify state change. */
- bs->ses_state = PTM_BFD_DOWN;
- control_notify(bs, bs->ses_state);
-
- /* Enable all timers. */
- bfd_recvtimer_update(bs);
- bfd_xmttimer_update(bs, bs->xmt_TO);
- }
- if (bpc->bpc_cbit) {
- if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_CBIT))
- return;
-
+ if (bpc->bpc_cbit)
SET_FLAG(bs->flags, BFD_SESS_FLAG_CBIT);
- } else {
- if (!CHECK_FLAG(bs->flags, BFD_SESS_FLAG_CBIT))
- return;
-
+ else
UNSET_FLAG(bs->flags, BFD_SESS_FLAG_CBIT);
- }
+
+ bs->peer_profile.echo_mode = bpc->bpc_echo;
+ bfd_set_echo(bs, bpc->bpc_echo);
+
+ /*
+ * Shutdown needs to be the last in order to avoid timers enable when
+ * the session is disabled.
+ */
+ bs->peer_profile.admin_shutdown = bpc->bpc_shutdown;
+ bfd_set_shutdown(bs, bpc->bpc_shutdown);
}
static int bfd_session_update(struct bfd_session *bs, struct bfd_peer_cfg *bpc)
@@ -666,6 +801,7 @@ void bfd_session_free(struct bfd_session *bs)
pl_free(bs->pl);
+ XFREE(MTYPE_BFDD_PROFILE, bs->profile_name);
XFREE(MTYPE_BFDD_CONFIG, bs);
}
@@ -1100,6 +1236,78 @@ void bs_set_slow_timers(struct bfd_session *bs)
bs->xmt_TO = BFD_DEF_SLOWTX;
}
+void bfd_set_echo(struct bfd_session *bs, bool echo)
+{
+ if (echo) {
+ /* Check if echo mode is already active. */
+ if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
+ return;
+
+ SET_FLAG(bs->flags, BFD_SESS_FLAG_ECHO);
+
+ /* Activate/update echo receive timeout timer. */
+ bs_echo_timer_handler(bs);
+ } else {
+ /* Check if echo mode is already disabled. */
+ if (!CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
+ return;
+
+ UNSET_FLAG(bs->flags, BFD_SESS_FLAG_ECHO);
+ ptm_bfd_echo_stop(bs);
+ }
+}
+
+void bfd_set_shutdown(struct bfd_session *bs, bool shutdown)
+{
+ bool is_shutdown;
+
+ /*
+ * Special case: we are batching changes and the previous state was
+ * not shutdown. Instead of potentially disconnect a running peer,
+ * we'll get the current status to validate we were really down.
+ */
+ if (bs->ses_state == PTM_BFD_UP)
+ is_shutdown = false;
+ else
+ is_shutdown = CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN);
+
+ if (shutdown) {
+ /* Already shutdown. */
+ if (is_shutdown)
+ return;
+
+ SET_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN);
+
+ /* Disable all events. */
+ bfd_recvtimer_delete(bs);
+ bfd_echo_recvtimer_delete(bs);
+ bfd_xmttimer_delete(bs);
+ bfd_echo_xmttimer_delete(bs);
+
+ /* Change and notify state change. */
+ bs->ses_state = PTM_BFD_ADM_DOWN;
+ control_notify(bs, bs->ses_state);
+
+ /* Don't try to send packets with a disabled session. */
+ if (bs->sock != -1)
+ ptm_bfd_snd(bs, 0);
+ } else {
+ /* Already working. */
+ if (!is_shutdown)
+ return;
+
+ UNSET_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN);
+
+ /* Change and notify state change. */
+ bs->ses_state = PTM_BFD_DOWN;
+ control_notify(bs, bs->ses_state);
+
+ /* Enable all timers. */
+ bfd_recvtimer_update(bs);
+ bfd_xmttimer_update(bs, bs->xmt_TO);
+ }
+}
+
/*
* Helper functions.
*/
@@ -1570,6 +1778,7 @@ void bfd_initialize(void)
"BFD session discriminator hash");
bfd_key_hash = hash_create(bfd_key_hash_do, bfd_key_hash_cmp,
"BFD session hash");
+ TAILQ_INIT(&bplist);
}
static void _bfd_free(struct hash_bucket *hb,
@@ -1582,6 +1791,8 @@ static void _bfd_free(struct hash_bucket *hb,
void bfd_shutdown(void)
{
+ struct bfd_profile *bp;
+
/*
* Close and free all BFD sessions.
*
@@ -1595,6 +1806,10 @@ void bfd_shutdown(void)
/* Now free the hashes themselves. */
hash_free(bfd_id_hash);
hash_free(bfd_key_hash);
+
+ /* Free all profile allocations. */
+ while ((bp = TAILQ_FIRST(&bplist)) != NULL)
+ bfd_profile_free(bp);
}
struct bfd_session_iterator {
@@ -1683,6 +1898,43 @@ void bfd_sessions_remove_manual(void)
}
/*
+ * Profile related hash functions.
+ */
+static void _bfd_profile_update(struct hash_bucket *hb, void *arg)
+{
+ struct bfd_profile *bp = arg;
+ struct bfd_session *bs = hb->data;
+
+ /* This session is not using the profile. */
+ if (bs->profile_name == NULL || strcmp(bs->profile_name, bp->name) != 0)
+ return;
+
+ bfd_profile_apply(bp->name, bs);
+}
+
+void bfd_profile_update(struct bfd_profile *bp)
+{
+ hash_iterate(bfd_key_hash, _bfd_profile_update, bp);
+}
+
+static void _bfd_profile_detach(struct hash_bucket *hb, void *arg)
+{
+ struct bfd_profile *bp = arg;
+ struct bfd_session *bs = hb->data;
+
+ /* This session is not using the profile. */
+ if (bs->profile_name == NULL || strcmp(bs->profile_name, bp->name) != 0)
+ return;
+
+ bfd_profile_remove(bs);
+}
+
+static void bfd_profile_detach(struct bfd_profile *bp)
+{
+ hash_iterate(bfd_key_hash, _bfd_profile_detach, bp);
+}
+
+/*
* VRF related functions.
*/
static int bfd_vrf_new(struct vrf *vrf)
diff --git a/bfdd/bfd.h b/bfdd/bfd.h
index 93873eed94..5984662a01 100644
--- a/bfdd/bfd.h
+++ b/bfdd/bfd.h
@@ -192,6 +192,34 @@ struct bfd_session_stats {
uint64_t znotification;
};
+/**
+ * BFD session profile to override default configurations.
+ */
+struct bfd_profile {
+ /** Profile name. */
+ char name[64];
+
+ /** Session detection multiplier. */
+ uint8_t detection_multiplier;
+ /** Desired transmission interval (in microseconds). */
+ uint32_t min_tx;
+ /** Minimum required receive interval (in microseconds). */
+ uint32_t min_rx;
+ /** Administrative state. */
+ bool admin_shutdown;
+
+ /** Echo mode (only applies to single hop). */
+ bool echo_mode;
+ /** Minimum required echo receive interval (in microseconds). */
+ uint32_t min_echo_rx;
+
+ /** Profile list entry. */
+ TAILQ_ENTRY(bfd_profile) entry;
+};
+
+/** Profile list type. */
+TAILQ_HEAD(bfdproflist, bfd_profile);
+
/* bfd_session shortcut label forwarding. */
struct peer_label;
@@ -210,6 +238,13 @@ struct bfd_session {
uint8_t mh_ttl;
uint8_t remote_cbit;
+ /** BFD profile name. */
+ char *profile_name;
+ /** BFD pre configured profile. */
+ struct bfd_profile *profile;
+ /** BFD peer configuration (without profile). */
+ struct bfd_profile peer_profile;
+
/* Timers */
struct bfd_timers timers;
struct bfd_timers cur_timers;
@@ -550,6 +585,22 @@ const struct bfd_session *bfd_session_next(const struct bfd_session *bs,
bool mhop);
void bfd_sessions_remove_manual(void);
+/**
+ * Set the BFD session echo state.
+ *
+ * \param bs the BFD session.
+ * \param echo the echo operational state.
+ */
+void bfd_set_echo(struct bfd_session *bs, bool echo);
+
+/**
+ * Set the BFD session functional state.
+ *
+ * \param bs the BFD session.
+ * \param shutdown the operational value.
+ */
+void bfd_set_shutdown(struct bfd_session *bs, bool shutdown);
+
/* BFD hash data structures interface */
void bfd_initialize(void);
void bfd_shutdown(void);
@@ -581,6 +632,57 @@ int bfd_echo_xmt_cb(struct thread *t);
extern struct in6_addr zero_addr;
+/**
+ * Creates a new profile entry and insert into the global list.
+ *
+ * \param name the BFD profile name.
+ *
+ * \returns `NULL` if it already exists otherwise the new entry.
+ */
+struct bfd_profile *bfd_profile_new(const char *name);
+
+/**
+ * Search for configured BFD profiles (profile name is case insensitive).
+ *
+ * \param name the BFD profile name.
+ *
+ * \returns `NULL` if it doesn't exist otherwise the entry.
+ */
+struct bfd_profile *bfd_profile_lookup(const char *name);
+
+/**
+ * Removes profile from list and free memory.
+ *
+ * \param bp the BFD profile.
+ */
+void bfd_profile_free(struct bfd_profile *bp);
+
+/**
+ * Apply a profile configuration to an existing BFD session. The non default
+ * values will not be overriden.
+ *
+ * NOTE: if the profile doesn't exist yet, then the profile will be applied
+ * once it begins to exist.
+ *
+ * \param profile_name the BFD profile name.
+ * \param bs the BFD session.
+ */
+void bfd_profile_apply(const char *profname, struct bfd_session *bs);
+
+/**
+ * Remove any applied profile from session and revert the session
+ * configuration.
+ *
+ * \param bs the BFD session.
+ */
+void bfd_profile_remove(struct bfd_session *bs);
+
+/**
+ * Apply new profile values to sessions using it.
+ *
+ * \param[in] bp the BFD profile that got updated.
+ */
+void bfd_profile_update(struct bfd_profile *bp);
/*
* bfdd_vty.c
diff --git a/bfdd/bfdd_cli.c b/bfdd/bfdd_cli.c
index 3e44fcb22a..166997e674 100644
--- a/bfdd/bfdd_cli.c
+++ b/bfdd/bfdd_cli.c
@@ -395,6 +395,125 @@ void bfd_cli_show_echo_interval(struct vty *vty, struct lyd_node *dnode,
}
}
+/*
+ * Profile commands.
+ */
+DEFPY_NOSH(bfd_profile, bfd_profile_cmd,
+ "profile WORD$name",
+ BFD_PROFILE_STR
+ BFD_PROFILE_NAME_STR)
+{
+ char xpath[XPATH_MAXLEN];
+ int rv;
+
+ snprintf(xpath, sizeof(xpath), "/frr-bfdd:bfdd/bfd/profile[name='%s']",
+ name);
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+
+ /* Apply settings immediately. */
+ rv = nb_cli_apply_changes(vty, NULL);
+ if (rv == CMD_SUCCESS)
+ VTY_PUSH_XPATH(BFD_PROFILE_NODE, xpath);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(no_bfd_profile, no_bfd_profile_cmd,
+ "no profile BFDPROF$name",
+ NO_STR
+ BFD_PROFILE_STR
+ BFD_PROFILE_NAME_STR)
+{
+ char xpath[XPATH_MAXLEN];
+
+ snprintf(xpath, sizeof(xpath), "/frr-bfdd:bfdd/bfd/profile[name='%s']",
+ name);
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+
+ /* Apply settings immediately. */
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void bfd_cli_show_profile(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ vty_out(vty, " profile %s\n", yang_dnode_get_string(dnode, "./name"));
+}
+
+ALIAS(bfd_peer_mult, bfd_profile_mult_cmd,
+ "detect-multiplier (2-255)$multiplier",
+ "Configure peer detection multiplier\n"
+ "Configure peer detection multiplier value\n")
+
+ALIAS(bfd_peer_tx, bfd_profile_tx_cmd,
+ "transmit-interval (10-60000)$interval",
+ "Configure peer transmit interval\n"
+ "Configure peer transmit interval value in milliseconds\n")
+
+ALIAS(bfd_peer_rx, bfd_profile_rx_cmd,
+ "receive-interval (10-60000)$interval",
+ "Configure peer receive interval\n"
+ "Configure peer receive interval value in milliseconds\n")
+
+ALIAS(bfd_peer_shutdown, bfd_profile_shutdown_cmd,
+ "[no] shutdown",
+ NO_STR
+ "Disable BFD peer\n")
+
+ALIAS(bfd_peer_echo, bfd_profile_echo_cmd,
+ "[no] echo-mode",
+ NO_STR
+ "Configure echo mode\n")
+
+ALIAS(bfd_peer_echo_interval, bfd_profile_echo_interval_cmd,
+ "echo-interval (10-60000)$interval",
+ "Configure peer echo interval\n"
+ "Configure peer echo interval value in milliseconds\n")
+
+DEFPY(bfd_peer_profile, bfd_peer_profile_cmd,
+ "[no] profile BFDPROF$pname",
+ NO_STR
+ "Use BFD profile settings\n"
+ BFD_PROFILE_NAME_STR)
+{
+ if (no)
+ nb_cli_enqueue_change(vty, "./profile", NB_OP_DESTROY, NULL);
+ else
+ nb_cli_enqueue_change(vty, "./profile", NB_OP_MODIFY, pname);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void bfd_cli_peer_profile_show(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ vty_out(vty, " profile %s\n", yang_dnode_get_string(dnode, NULL));
+}
+
+struct cmd_node bfd_profile_node = {
+ .name = "bfd profile",
+ .node = BFD_PROFILE_NODE,
+ .parent_node = BFD_NODE,
+ .prompt = "%s(config-bfd-profile)# ",
+};
+
+static void bfd_profile_var(vector comps, struct cmd_token *token)
+{
+ extern struct bfdproflist bplist;
+ struct bfd_profile *bp;
+
+ TAILQ_FOREACH (bp, &bplist, entry) {
+ vector_set(comps, XSTRDUP(MTYPE_COMPLETION, bp->name));
+ }
+}
+
+static const struct cmd_variable_handler bfd_vars[] = {
+ {.tokenname = "BFDPROF", .completions = bfd_profile_var},
+ {.completions = NULL}
+};
+
void
bfdd_cli_init(void)
{
@@ -410,4 +529,21 @@ bfdd_cli_init(void)
install_element(BFD_PEER_NODE, &bfd_peer_tx_cmd);
install_element(BFD_PEER_NODE, &bfd_peer_echo_cmd);
install_element(BFD_PEER_NODE, &bfd_peer_echo_interval_cmd);
+ install_element(BFD_PEER_NODE, &bfd_peer_profile_cmd);
+
+ /* Profile commands. */
+ cmd_variable_handler_register(bfd_vars);
+
+ install_node(&bfd_profile_node);
+ install_default(BFD_PROFILE_NODE);
+
+ install_element(BFD_NODE, &bfd_profile_cmd);
+ install_element(BFD_NODE, &no_bfd_profile_cmd);
+
+ install_element(BFD_PROFILE_NODE, &bfd_profile_mult_cmd);
+ install_element(BFD_PROFILE_NODE, &bfd_profile_tx_cmd);
+ install_element(BFD_PROFILE_NODE, &bfd_profile_rx_cmd);
+ install_element(BFD_PROFILE_NODE, &bfd_profile_shutdown_cmd);
+ install_element(BFD_PROFILE_NODE, &bfd_profile_echo_cmd);
+ install_element(BFD_PROFILE_NODE, &bfd_profile_echo_interval_cmd);
}
diff --git a/bfdd/bfdd_nb.c b/bfdd/bfdd_nb.c
index 8d46742337..2ff99ca608 100644
--- a/bfdd/bfdd_nb.c
+++ b/bfdd/bfdd_nb.c
@@ -41,6 +41,57 @@ const struct frr_yang_module_info frr_bfdd_info = {
}
},
{
+ .xpath = "/frr-bfdd:bfdd/bfd/profile",
+ .cbs = {
+ .create = bfdd_bfd_profile_create,
+ .destroy = bfdd_bfd_profile_destroy,
+ .cli_show = bfd_cli_show_profile,
+ .cli_show_end = bfd_cli_show_peer_end,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/profile/detection-multiplier",
+ .cbs = {
+ .modify = bfdd_bfd_profile_detection_multiplier_modify,
+ .cli_show = bfd_cli_show_mult,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/profile/desired-transmission-interval",
+ .cbs = {
+ .modify = bfdd_bfd_profile_desired_transmission_interval_modify,
+ .cli_show = bfd_cli_show_tx,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/profile/required-receive-interval",
+ .cbs = {
+ .modify = bfdd_bfd_profile_required_receive_interval_modify,
+ .cli_show = bfd_cli_show_rx,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/profile/administrative-down",
+ .cbs = {
+ .modify = bfdd_bfd_profile_administrative_down_modify,
+ .cli_show = bfd_cli_show_shutdown,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/profile/echo-mode",
+ .cbs = {
+ .modify = bfdd_bfd_profile_echo_mode_modify,
+ .cli_show = bfd_cli_show_echo,
+ }
+ },
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/profile/desired-echo-transmission-interval",
+ .cbs = {
+ .modify = bfdd_bfd_profile_desired_echo_transmission_interval_modify,
+ .cli_show = bfd_cli_show_echo_interval,
+ }
+ },
+ {
.xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop",
.cbs = {
.create = bfdd_bfd_sessions_single_hop_create,
@@ -59,6 +110,14 @@ const struct frr_yang_module_info frr_bfdd_info = {
.destroy = bfdd_bfd_sessions_single_hop_source_addr_destroy,
}
},
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/profile",
+ .cbs = {
+ .modify = bfdd_bfd_sessions_single_hop_profile_modify,
+ .destroy = bfdd_bfd_sessions_single_hop_profile_destroy,
+ .cli_show = bfd_cli_peer_profile_show,
+ }
+ },
{
.xpath = "/frr-bfdd:bfdd/bfd/sessions/single-hop/detection-multiplier",
.cbs = {
@@ -233,6 +292,14 @@ const struct frr_yang_module_info frr_bfdd_info = {
.cli_show_end = bfd_cli_show_peer_end,
}
},
+ {
+ .xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/profile",
+ .cbs = {
+ .modify = bfdd_bfd_sessions_single_hop_profile_modify,
+ .destroy = bfdd_bfd_sessions_single_hop_profile_destroy,
+ .cli_show = bfd_cli_peer_profile_show,
+ }
+ },
{
.xpath = "/frr-bfdd:bfdd/bfd/sessions/multi-hop/detection-multiplier",
.cbs = {
diff --git a/bfdd/bfdd_nb.h b/bfdd/bfdd_nb.h
index 4fba3a0d30..a379c2135e 100644
--- a/bfdd/bfdd_nb.h
+++ b/bfdd/bfdd_nb.h
@@ -28,6 +28,18 @@ extern const struct frr_yang_module_info frr_bfdd_info;
/* Mandatory callbacks. */
int bfdd_bfd_create(struct nb_cb_create_args *args);
int bfdd_bfd_destroy(struct nb_cb_destroy_args *args);
+int bfdd_bfd_profile_create(struct nb_cb_create_args *args);
+int bfdd_bfd_profile_destroy(struct nb_cb_destroy_args *args);
+int bfdd_bfd_profile_detection_multiplier_modify(
+ struct nb_cb_modify_args *args);
+int bfdd_bfd_profile_desired_transmission_interval_modify(
+ struct nb_cb_modify_args *args);
+int bfdd_bfd_profile_required_receive_interval_modify(
+ struct nb_cb_modify_args *args);
+int bfdd_bfd_profile_administrative_down_modify(struct nb_cb_modify_args *args);
+int bfdd_bfd_profile_echo_mode_modify(struct nb_cb_modify_args *args);
+int bfdd_bfd_profile_desired_echo_transmission_interval_modify(
+ struct nb_cb_modify_args *args);
int bfdd_bfd_sessions_single_hop_create(struct nb_cb_create_args *args);
int bfdd_bfd_sessions_single_hop_destroy(struct nb_cb_destroy_args *args);
const void *
@@ -39,6 +51,9 @@ int bfdd_bfd_sessions_single_hop_source_addr_modify(
struct nb_cb_modify_args *args);
int bfdd_bfd_sessions_single_hop_source_addr_destroy(
struct nb_cb_destroy_args *args);
+int bfdd_bfd_sessions_single_hop_profile_modify(struct nb_cb_modify_args *args);
+int bfdd_bfd_sessions_single_hop_profile_destroy(
+ struct nb_cb_destroy_args *args);
int bfdd_bfd_sessions_single_hop_detection_multiplier_modify(
struct nb_cb_modify_args *args);
int bfdd_bfd_sessions_single_hop_desired_transmission_interval_modify(
@@ -187,5 +202,9 @@ void bfd_cli_show_echo(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
void bfd_cli_show_echo_interval(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
+void bfd_cli_show_profile(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void bfd_cli_peer_profile_show(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
#endif /* _FRR_BFDD_NB_H_ */
diff --git a/bfdd/bfdd_nb_config.c b/bfdd/bfdd_nb_config.c
index 9e136c3fc5..de11997d1a 100644
--- a/bfdd/bfdd_nb_config.c
+++ b/bfdd/bfdd_nb_config.c
@@ -215,6 +215,211 @@ int bfdd_bfd_destroy(struct nb_cb_destroy_args *args)
}
/*
+ * XPath: /frr-bfdd:bfdd/bfd/profile
+ */
+int bfdd_bfd_profile_create(struct nb_cb_create_args *args)
+{
+ struct bfd_profile *bp;
+ const char *name;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ name = yang_dnode_get_string(args->dnode, "./name");
+ bp = bfd_profile_new(name);
+ nb_running_set_entry(args->dnode, bp);
+
+ return NB_OK;
+}
+
+int bfdd_bfd_profile_destroy(struct nb_cb_destroy_args *args)
+{
+ struct bfd_profile *bp;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ bp = nb_running_unset_entry(args->dnode);
+ bfd_profile_free(bp);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-bfdd:bfdd/bfd/profile/detection-multiplier
+ */
+int bfdd_bfd_profile_detection_multiplier_modify(struct nb_cb_modify_args *args)
+{
+ struct bfd_profile *bp;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ bp = nb_running_get_entry(args->dnode, NULL, true);
+ bp->detection_multiplier = yang_dnode_get_uint8(args->dnode, NULL);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-bfdd:bfdd/bfd/profile/desired-transmission-interval
+ */
+int bfdd_bfd_profile_desired_transmission_interval_modify(
+ struct nb_cb_modify_args *args)
+{
+ struct bfd_profile *bp;
+ uint32_t min_tx;
+
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ min_tx = yang_dnode_get_uint32(args->dnode, NULL);
+ if (min_tx < 10000 || min_tx > 60000000)
+ return NB_ERR_VALIDATION;
+ break;
+
+ case NB_EV_PREPARE:
+ /* NOTHING */
+ break;
+
+ case NB_EV_APPLY:
+ min_tx = yang_dnode_get_uint32(args->dnode, NULL);
+ bp = nb_running_get_entry(args->dnode, NULL, true);
+ if (bp->min_tx == min_tx)
+ return NB_OK;
+
+ bp->min_tx = min_tx;
+ bfd_profile_update(bp);
+ break;
+
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-bfdd:bfdd/bfd/profile/required-receive-interval
+ */
+int bfdd_bfd_profile_required_receive_interval_modify(
+ struct nb_cb_modify_args *args)
+{
+ struct bfd_profile *bp;
+ uint32_t min_rx;
+
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ min_rx = yang_dnode_get_uint32(args->dnode, NULL);
+ if (min_rx < 10000 || min_rx > 60000000)
+ return NB_ERR_VALIDATION;
+ break;
+
+ case NB_EV_PREPARE:
+ /* NOTHING */
+ break;
+
+ case NB_EV_APPLY:
+ min_rx = yang_dnode_get_uint32(args->dnode, NULL);
+ bp = nb_running_get_entry(args->dnode, NULL, true);
+ if (bp->min_rx == min_rx)
+ return NB_OK;
+
+ bp->min_rx = min_rx;
+ bfd_profile_update(bp);
+ break;
+
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-bfdd:bfdd/bfd/profile/administrative-down
+ */
+int bfdd_bfd_profile_administrative_down_modify(struct nb_cb_modify_args *args)
+{
+ struct bfd_profile *bp;
+ bool shutdown;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ shutdown = yang_dnode_get_bool(args->dnode, NULL);
+ bp = nb_running_get_entry(args->dnode, NULL, true);
+ if (bp->admin_shutdown == shutdown)
+ return NB_OK;
+
+ bp->admin_shutdown = shutdown;
+ bfd_profile_update(bp);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-bfdd:bfdd/bfd/profile/echo-mode
+ */
+int bfdd_bfd_profile_echo_mode_modify(struct nb_cb_modify_args *args)
+{
+ struct bfd_profile *bp;
+ bool echo;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ echo = yang_dnode_get_bool(args->dnode, NULL);
+ bp = nb_running_get_entry(args->dnode, NULL, true);
+ if (bp->echo_mode == echo)
+ return NB_OK;
+
+ bp->echo_mode = echo;
+ bfd_profile_update(bp);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-bfdd:bfdd/bfd/profile/desired-echo-echo-transmission-interval
+ */
+int bfdd_bfd_profile_desired_echo_transmission_interval_modify(
+ struct nb_cb_modify_args *args)
+{
+ struct bfd_profile *bp;
+ uint32_t min_rx;
+
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ min_rx = yang_dnode_get_uint32(args->dnode, NULL);
+ if (min_rx < 10000 || min_rx > 60000000)
+ return NB_ERR_VALIDATION;
+ break;
+
+ case NB_EV_PREPARE:
+ /* NOTHING */
+ break;
+
+ case NB_EV_APPLY:
+ min_rx = yang_dnode_get_uint32(args->dnode, NULL);
+ bp = nb_running_get_entry(args->dnode, NULL, true);
+ if (bp->min_echo_rx == min_rx)
+ return NB_OK;
+
+ bp->min_echo_rx = min_rx;
+ bfd_profile_update(bp);
+ break;
+
+ case NB_EV_ABORT:
+ /* NOTHING */
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
* XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop
*/
int bfdd_bfd_sessions_single_hop_create(struct nb_cb_create_args *args)
@@ -244,6 +449,36 @@ int bfdd_bfd_sessions_single_hop_source_addr_destroy(
}
/*
+ * XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/profile
+ */
+int bfdd_bfd_sessions_single_hop_profile_modify(struct nb_cb_modify_args *args)
+{
+ struct bfd_session *bs;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ bs = nb_running_get_entry(args->dnode, NULL, true);
+ bfd_profile_apply(yang_dnode_get_string(args->dnode, NULL), bs);
+
+ return NB_OK;
+}
+
+int bfdd_bfd_sessions_single_hop_profile_destroy(
+ struct nb_cb_destroy_args *args)
+{
+ struct bfd_session *bs;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ bs = nb_running_get_entry(args->dnode, NULL, true);
+ bfd_profile_remove(bs);
+
+ return NB_OK;
+}
+
+/*
* XPath: /frr-bfdd:bfdd/bfd/sessions/single-hop/detection-multiplier
*/
int bfdd_bfd_sessions_single_hop_detection_multiplier_modify(
@@ -263,6 +498,7 @@ int bfdd_bfd_sessions_single_hop_detection_multiplier_modify(
case NB_EV_APPLY:
bs = nb_running_get_entry(args->dnode, NULL, true);
bs->detect_mult = detection_multiplier;
+ bs->peer_profile.detection_multiplier = detection_multiplier;
break;
case NB_EV_ABORT:
@@ -298,6 +534,7 @@ int bfdd_bfd_sessions_single_hop_desired_transmission_interval_modify(
return NB_OK;
bs->timers.desired_min_tx = tx_interval;
+ bs->peer_profile.min_tx = tx_interval;
bfd_set_polling(bs);
break;
@@ -334,6 +571,7 @@ int bfdd_bfd_sessions_single_hop_required_receive_interval_modify(
return NB_OK;
bs->timers.required_min_rx = rx_interval;
+ bs->peer_profile.min_rx = rx_interval;
bfd_set_polling(bs);
break;
@@ -367,42 +605,8 @@ int bfdd_bfd_sessions_single_hop_administrative_down_modify(
}
bs = nb_running_get_entry(args->dnode, NULL, true);
-
- if (!shutdown) {
- if (!CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
- return NB_OK;
-
- UNSET_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN);
-
- /* Change and notify state change. */
- bs->ses_state = PTM_BFD_DOWN;
- control_notify(bs, bs->ses_state);
-
- /* Enable all timers. */
- bfd_recvtimer_update(bs);
- bfd_xmttimer_update(bs, bs->xmt_TO);
- if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO)) {
- bfd_echo_recvtimer_update(bs);
- bfd_echo_xmttimer_update(bs, bs->echo_xmt_TO);
- }
- } else {
- if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
- return NB_OK;
-
- SET_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN);
-
- /* Disable all events. */
- bfd_recvtimer_delete(bs);
- bfd_echo_recvtimer_delete(bs);
- bfd_xmttimer_delete(bs);
- bfd_echo_xmttimer_delete(bs);
-
- /* Change and notify state change. */
- bs->ses_state = PTM_BFD_ADM_DOWN;
- control_notify(bs, bs->ses_state);
-
- ptm_bfd_snd(bs, 0);
- }
+ bs->peer_profile.admin_shutdown = shutdown;
+ bfd_set_shutdown(bs, shutdown);
return NB_OK;
}
@@ -429,22 +633,8 @@ int bfdd_bfd_sessions_single_hop_echo_mode_modify(
}
bs = nb_running_get_entry(args->dnode, NULL, true);
-
- if (!echo) {
- if (!CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
- return NB_OK;
-
- UNSET_FLAG(bs->flags, BFD_SESS_FLAG_ECHO);
- ptm_bfd_echo_stop(bs);
- } else {
- if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO))
- return NB_OK;
-
- SET_FLAG(bs->flags, BFD_SESS_FLAG_ECHO);
- /* Apply setting immediately. */
- if (!CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN))
- bs_echo_timer_handler(bs);
- }
+ bs->peer_profile.echo_mode = echo;
+ bfd_set_echo(bs, echo);
return NB_OK;
}
@@ -475,6 +665,7 @@ int bfdd_bfd_sessions_single_hop_desired_echo_transmission_interval_modify(
return NB_OK;
bs->timers.required_min_echo = echo_interval;
+ bs->peer_profile.min_echo_rx = echo_interval;
break;
case NB_EV_ABORT:
diff --git a/bfdd/ptm_adapter.c b/bfdd/ptm_adapter.c
index 7efbd2c7b8..25938dd9f5 100644
--- a/bfdd/ptm_adapter.c
+++ b/bfdd/ptm_adapter.c
@@ -417,6 +417,9 @@ static void bfdd_dest_register(struct stream *msg, vrf_id_t vrf_id)
"ptm-add-dest: failed to create BFD session");
return;
}
+
+ /* Protocol created peers are 'no shutdown' by default. */
+ bs->peer_profile.admin_shutdown = false;
} else {
/* Don't try to change echo/shutdown state. */
bpc.bpc_echo = CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO);
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index c44a822d11..29cc9ac1eb 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -2634,17 +2634,17 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
afi_t afi = 0;
safi_t safi = 0;
char buf[PREFIX_STRLEN];
- char buf1[PREFIX_STRLEN];
+ bool new_pi = false;
memset(pp, 0, sizeof(struct prefix));
ip_prefix_from_evpn_prefix(evp, pp);
if (bgp_debug_zebra(NULL)) {
zlog_debug(
- "import evpn prefix %s as ip prefix %s in vrf %s",
+ "vrf %s: import evpn prefix %s parent %p flags 0x%x",
+ vrf_id_to_name(bgp_vrf->vrf_id),
prefix2str(evp, buf, sizeof(buf)),
- prefix2str(pp, buf1, sizeof(buf)),
- vrf_id_to_name(bgp_vrf->vrf_id));
+ parent_pi, parent_pi->flags);
}
/* Create (or fetch) route within the VRF. */
@@ -2678,9 +2678,10 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
&& (struct bgp_path_info *)pi->extra->parent == parent_pi)
break;
- if (!pi)
+ if (!pi) {
pi = bgp_create_evpn_bgp_path_info(parent_pi, rn, &attr);
- else {
+ new_pi = true;
+ } else {
if (attrhash_cmp(pi->attr, &attr)
&& !CHECK_FLAG(pi->flags, BGP_PATH_REMOVED)) {
bgp_unlock_node(rn);
@@ -2722,6 +2723,12 @@ static int install_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
bgp_unlock_node(rn);
+ if (bgp_debug_zebra(NULL))
+ zlog_debug(
+ "... %s pi rn %p (l %d) pi %p (l %d, f 0x%x)",
+ new_pi ? "new" : "update",
+ rn, rn->lock, pi, pi->lock, pi->flags);
+
return ret;
}
@@ -2839,17 +2846,16 @@ static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
afi_t afi = 0;
safi_t safi = 0;
char buf[PREFIX_STRLEN];
- char buf1[PREFIX_STRLEN];
memset(pp, 0, sizeof(struct prefix));
ip_prefix_from_evpn_prefix(evp, pp);
if (bgp_debug_zebra(NULL)) {
zlog_debug(
- "uninstalling evpn prefix %s as ip prefix %s in vrf %s",
+ "vrf %s: unimport evpn prefix %s parent %p flags 0x%x",
+ vrf_id_to_name(bgp_vrf->vrf_id),
prefix2str(evp, buf, sizeof(buf)),
- prefix2str(pp, buf1, sizeof(buf)),
- vrf_id_to_name(bgp_vrf->vrf_id));
+ parent_pi, parent_pi->flags);
}
/* Locate route within the VRF. */
@@ -2876,6 +2882,11 @@ static int uninstall_evpn_route_entry_in_vrf(struct bgp *bgp_vrf,
if (!pi)
return 0;
+ if (bgp_debug_zebra(NULL))
+ zlog_debug(
+ "... delete rn %p (l %d) pi %p (l %d, f 0x%x)",
+ rn, rn->lock, pi, pi->lock, pi->flags);
+
/* Process for route leaking. */
vpn_leak_from_vrf_withdraw(bgp_get_default(), bgp_vrf, pi);
@@ -6321,16 +6332,17 @@ bool bgp_evpn_is_prefix_nht_supported(const struct prefix *pfx)
struct prefix_evpn *evp = (struct prefix_evpn *)pfx;
/*
- * EVPN RT-5 should not be marked as valid and imported to vrfs if the
- * BGP nexthop is not reachable. To check for the nexthop reachability,
- * Add nexthop for EVPN RT-5 for nexthop tracking.
- *
- * Ideally, a BGP route should be marked as valid only if the
- * nexthop is reachable. Thus, other EVPN route types also should be
- * added here after testing is performed for them.
+ * EVPN routes should be marked as valid only if the nexthop is
+ * reachable. Only if this happens, the route should be imported
+ * (into VNI or VRF routing tables) and/or advertised.
+ * Note: This is currently applied for EVPN type-2, type-3 and
+ * type-5 routes. It may be tweaked later on for other routes, or
+ * even removed completely when all routes are handled.
*/
if (pfx && pfx->family == AF_EVPN &&
- evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE)
+ (evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE ||
+ evp->prefix.route_type == BGP_EVPN_IMET_ROUTE ||
+ evp->prefix.route_type == BGP_EVPN_IP_PREFIX_ROUTE))
return true;
return false;
diff --git a/bgpd/bgp_filter.c b/bgpd/bgp_filter.c
index 3e26263df1..0308a30d54 100644
--- a/bgpd/bgp_filter.c
+++ b/bgpd/bgp_filter.c
@@ -548,15 +548,6 @@ DEFUN (no_as_path_all,
return CMD_SUCCESS;
}
-ALIAS (no_as_path_all,
- no_ip_as_path_all_cmd,
- "no ip as-path access-list WORD",
- NO_STR
- IP_STR
- "BGP autonomous system path filter\n"
- "Specify an access list name\n"
- "Regular expression access list name\n")
-
static void as_list_show(struct vty *vty, struct as_list *aslist)
{
struct as_filter *asfilter;
@@ -683,7 +674,6 @@ void bgp_filter_init(void)
install_element(CONFIG_NODE, &bgp_as_path_cmd);
install_element(CONFIG_NODE, &no_bgp_as_path_cmd);
install_element(CONFIG_NODE, &no_bgp_as_path_all_cmd);
- install_element(CONFIG_NODE, &no_ip_as_path_all_cmd);
install_element(VIEW_NODE, &show_bgp_as_path_access_list_cmd);
install_element(VIEW_NODE, &show_ip_as_path_access_list_cmd);
diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c
index bfce61c2af..ff238d71b1 100644
--- a/bgpd/bgp_nexthop.c
+++ b/bgpd/bgp_nexthop.c
@@ -44,6 +44,7 @@
#include "bgpd/bgp_damp.h"
#include "bgpd/bgp_fsm.h"
#include "bgpd/bgp_vty.h"
+#include "bgpd/bgp_rd.h"
DEFINE_MTYPE_STATIC(BGPD, MARTIAN_STRING, "BGP Martian Address Intf String");
@@ -695,13 +696,44 @@ bool bgp_subgrp_multiaccess_check_v4(struct in_addr nexthop,
return false;
}
+static void bgp_show_nexthop_paths(struct vty *vty, struct bgp *bgp,
+ struct bgp_nexthop_cache *bnc)
+{
+ struct bgp_node *rn;
+ struct bgp_path_info *path;
+ int afi;
+ safi_t safi;
+ struct bgp_table *table;
+ struct bgp *bgp_path;
+ char buf1[BUFSIZ];
+
+ vty_out(vty, " Paths:\n");
+ LIST_FOREACH (path, &(bnc->paths), nh_thread) {
+ rn = path->net;
+ assert(rn && bgp_node_table(rn));
+ afi = family2afi(rn->p.family);
+ table = bgp_node_table(rn);
+ safi = table->safi;
+ bgp_path = table->bgp;
+
+ if (rn->prn) {
+ prefix_rd2str((struct prefix_rd *)&rn->prn->p,
+ buf1, sizeof(buf1));
+ vty_out(vty, " %d/%d %pRN RD %s %s flags 0x%x\n",
+ afi, safi, rn, buf1, bgp_path->name_pretty, path->flags);
+ } else
+ vty_out(vty, " %d/%d %pRN %s flags 0x%x\n",
+ afi, safi, rn, bgp_path->name_pretty, path->flags);
+ }
+}
+
static void bgp_show_nexthops_detail(struct vty *vty, struct bgp *bgp,
struct bgp_nexthop_cache *bnc)
{
char buf[PREFIX2STR_BUFFER];
struct nexthop *nexthop;
- for (nexthop = bnc->nexthop; nexthop; nexthop = nexthop->next)
+ for (nexthop = bnc->nexthop; nexthop; nexthop = nexthop->next) {
switch (nexthop->type) {
case NEXTHOP_TYPE_IPV6:
vty_out(vty, " gate %s\n",
@@ -736,15 +768,55 @@ static void bgp_show_nexthops_detail(struct vty *vty, struct bgp *bgp,
vty_out(vty, " invalid nexthop type %u\n",
nexthop->type);
}
+ }
}
-static void bgp_show_nexthops(struct vty *vty, struct bgp *bgp, int detail,
- bool import_table)
+static void bgp_show_nexthop(struct vty *vty, struct bgp *bgp,
+ struct bgp_node *rn,
+ struct bgp_nexthop_cache *bnc,
+ bool specific)
{
- struct bgp_node *rn;
- struct bgp_nexthop_cache *bnc;
char buf[PREFIX2STR_BUFFER];
time_t tbuf;
+ struct peer *peer;
+ const struct prefix *p = bgp_node_get_prefix(rn);
+
+ peer = (struct peer *)bnc->nht_info;
+
+ 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)),
+ bnc->metric, bnc->path_count);
+ if (peer)
+ vty_out(vty, ", peer %s", peer->host);
+ vty_out(vty, "\n");
+ 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)),
+ bnc->path_count);
+ if (peer)
+ vty_out(vty, ", peer %s", peer->host);
+ vty_out(vty, "\n");
+ if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED))
+ vty_out(vty, " Must be Connected\n");
+ if (!CHECK_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED))
+ vty_out(vty, " Is not Registered\n");
+ }
+ tbuf = time(NULL) - (bgp_clock() - bnc->last_update);
+ vty_out(vty, " Last update: %s", ctime(&tbuf));
+ vty_out(vty, "\n");
+
+ /* show paths dependent on nexthop, if needed. */
+ if (specific)
+ bgp_show_nexthop_paths(vty, bgp, bnc);
+}
+
+static void bgp_show_nexthops(struct vty *vty, struct bgp *bgp,
+ bool import_table)
+{
+ struct bgp_node *rn;
+ struct bgp_nexthop_cache *bnc;
afi_t afi;
struct bgp_table **table;
@@ -761,52 +833,17 @@ static void bgp_show_nexthops(struct vty *vty, struct bgp *bgp, int detail,
continue;
for (rn = bgp_table_top(table[afi]); rn;
rn = bgp_route_next(rn)) {
- struct peer *peer;
- const struct prefix *p = bgp_node_get_prefix(rn);
-
bnc = bgp_node_get_bgp_nexthop_info(rn);
if (!bnc)
continue;
- peer = (struct peer *)bnc->nht_info;
-
- 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)),
- bnc->metric, bnc->path_count);
- if (peer)
- vty_out(vty, ", peer %s", peer->host);
- vty_out(vty, "\n");
-
- if (!detail)
- continue;
-
- bgp_show_nexthops_detail(vty, bgp, bnc);
-
- } else {
- vty_out(vty, " %s invalid",
- inet_ntop(p->family, &p->u.prefix, buf,
- sizeof(buf)));
- if (peer)
- vty_out(vty, ", peer %s", peer->host);
- vty_out(vty, "\n");
- if (CHECK_FLAG(bnc->flags,
- BGP_NEXTHOP_CONNECTED))
- vty_out(vty, " Must be Connected\n");
- if (!CHECK_FLAG(bnc->flags,
- BGP_NEXTHOP_REGISTERED))
- vty_out(vty, " Is not Registered\n");
- }
- tbuf = time(NULL) - (bgp_clock() - bnc->last_update);
- vty_out(vty, " Last update: %s", ctime(&tbuf));
- vty_out(vty, "\n");
+ bgp_show_nexthop(vty, bgp, rn, bnc, false);
}
}
}
static int show_ip_bgp_nexthop_table(struct vty *vty, const char *name,
- int detail, bool import_table)
+ const char *nhopip_str,
+ bool import_table)
{
struct bgp *bgp;
@@ -819,7 +856,31 @@ static int show_ip_bgp_nexthop_table(struct vty *vty, const char *name,
return CMD_WARNING;
}
- bgp_show_nexthops(vty, bgp, detail, import_table);
+ if (nhopip_str) {
+ struct prefix nhop;
+ struct bgp_table **table;
+ struct bgp_node *rn;
+ 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;
+ rn = bgp_node_lookup(table[family2afi(nhop.family)], &nhop);
+ if (!rn) {
+ vty_out(vty, "specified nexthop is not found\n");
+ return CMD_SUCCESS;
+ }
+ bnc = bgp_node_get_bgp_nexthop_info(rn);
+ if (!bnc) {
+ vty_out(vty, "specified nexthop does not have entry\n");
+ return CMD_SUCCESS;
+ }
+ bgp_show_nexthop(vty, bgp, rn, bnc, true);
+ } else
+ bgp_show_nexthops(vty, bgp, import_table);
return CMD_SUCCESS;
}
@@ -834,29 +895,36 @@ static void bgp_show_all_instances_nexthops_vty(struct vty *vty)
(bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)
? VRF_DEFAULT_NAME
: bgp->name);
- bgp_show_nexthops(vty, bgp, 0, false);
+ bgp_show_nexthops(vty, bgp, false);
}
}
DEFUN (show_ip_bgp_nexthop,
show_ip_bgp_nexthop_cmd,
- "show [ip] bgp [<view|vrf> VIEWVRFNAME] nexthop [detail]",
+ "show [ip] bgp [<view|vrf> VIEWVRFNAME] nexthop [<A.B.C.D|X:X::X:X>] [detail]",
SHOW_STR
IP_STR
BGP_STR
BGP_INSTANCE_HELP_STR
"BGP nexthop table\n"
+ "IPv4 nexthop address\n"
+ "IPv6 nexthop address\n"
"Show detailed information\n")
{
int idx = 0;
+ int nh_idx = 0;
char *vrf = NULL;
+ char *nhop_ip = NULL;
if (argv_find(argv, argc, "view", &idx)
|| argv_find(argv, argc, "vrf", &idx))
vrf = argv[++idx]->arg;
- int detail = argv_find(argv, argc, "detail", &idx) ? 1 : 0;
- return show_ip_bgp_nexthop_table(vty, vrf, detail, false);
+ if (argv_find(argv, argc, "A.B.C.D", &nh_idx)
+ || argv_find(argv, argc, "X:X::X:X", &nh_idx))
+ nhop_ip = argv[nh_idx]->arg;
+
+ return show_ip_bgp_nexthop_table(vty, vrf, nhop_ip, false);
}
DEFUN (show_ip_bgp_import_check,
@@ -875,8 +943,8 @@ DEFUN (show_ip_bgp_import_check,
if (argv_find(argv, argc, "view", &idx)
|| argv_find(argv, argc, "vrf", &idx))
vrf = argv[++idx]->arg;
- int detail = argv_find(argv, argc, "detail", &idx) ? 1 : 0;
- return show_ip_bgp_nexthop_table(vty, vrf, detail, true);
+
+ return show_ip_bgp_nexthop_table(vty, vrf, NULL, true);
}
DEFUN (show_ip_bgp_instance_all_nexthop,
diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c
index fced2fbcab..e3b05e8b79 100644
--- a/bgpd/bgp_nht.c
+++ b/bgpd/bgp_nht.c
@@ -44,6 +44,7 @@
#include "bgpd/bgp_zebra.h"
#include "bgpd/bgp_flowspec_util.h"
#include "bgpd/bgp_evpn.h"
+#include "bgpd/bgp_rd.h"
extern struct zclient *zclient;
@@ -700,7 +701,7 @@ 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",
+ "NH update for %s %s flags 0x%x chgflags 0x%x - evaluate paths",
buf, bnc->bgp->name_pretty, bnc->flags,
bnc->change_flags);
}
@@ -735,7 +736,8 @@ static void evaluate_paths(struct bgp_nexthop_cache *bnc)
* nexthops with labels
*/
- int bnc_is_valid_nexthop = 0;
+ bool bnc_is_valid_nexthop = false;
+ bool path_valid = false;
if (safi == SAFI_UNICAST &&
path->sub_type == BGP_ROUTE_IMPORTED &&
@@ -743,7 +745,7 @@ static void evaluate_paths(struct bgp_nexthop_cache *bnc)
path->extra->num_labels) {
bnc_is_valid_nexthop =
- bgp_isvalid_labeled_nexthop(bnc) ? 1 : 0;
+ bgp_isvalid_labeled_nexthop(bnc) ? true : false;
} else {
if (bgp_update_martian_nexthop(
bnc->bgp, afi, safi, path->type,
@@ -754,29 +756,31 @@ static void evaluate_paths(struct bgp_nexthop_cache *bnc)
__func__, rn, bgp_path->name);
} else
bnc_is_valid_nexthop =
- bgp_isvalid_nexthop(bnc) ? 1 : 0;
+ bgp_isvalid_nexthop(bnc) ? true : false;
}
- if (BGP_DEBUG(nht, NHT))
- zlog_debug("%s: prefix %pRN (vrf %s) %svalid", __func__,
- rn, bgp_path->name,
- (bnc_is_valid_nexthop ? "" : "not "));
+ if (BGP_DEBUG(nht, NHT)) {
+ char buf1[RD_ADDRSTRLEN];
- if ((CHECK_FLAG(path->flags, BGP_PATH_VALID) ? 1 : 0)
- != bnc_is_valid_nexthop) {
- if (CHECK_FLAG(path->flags, BGP_PATH_VALID)) {
- bgp_aggregate_decrement(bgp_path, p, path, afi,
- safi);
- bgp_path_info_unset_flag(rn, path,
- BGP_PATH_VALID);
- } else {
- bgp_path_info_set_flag(rn, path,
- BGP_PATH_VALID);
- bgp_aggregate_increment(bgp_path, p, path, afi,
- safi);
- }
+ if (rn->prn) {
+ prefix_rd2str((struct prefix_rd *)&rn->prn->p,
+ buf1, sizeof(buf1));
+ zlog_debug(
+ "... eval path %d/%d %pRN RD %s %s flags 0x%x",
+ afi, safi, rn, buf1,
+ bgp_path->name_pretty, path->flags);
+ } else
+ zlog_debug(
+ "... eval path %d/%d %pRN %s flags 0x%x",
+ afi, safi, rn, bgp_path->name_pretty,
+ path->flags);
}
+ /* Skip paths marked for removal or as history. */
+ if (CHECK_FLAG(path->flags, BGP_PATH_REMOVED)
+ || CHECK_FLAG(path->flags, BGP_PATH_HISTORY))
+ continue;
+
/* Copy the metric to the path. Will be used for bestpath
* computation */
if (bgp_isvalid_nexthop(bnc) && bnc->metric)
@@ -789,13 +793,33 @@ static void evaluate_paths(struct bgp_nexthop_cache *bnc)
|| CHECK_FLAG(bnc->change_flags, BGP_NEXTHOP_CHANGED))
SET_FLAG(path->flags, BGP_PATH_IGP_CHANGED);
- if (safi == SAFI_EVPN && bgp_evpn_is_prefix_nht_supported(p)) {
- if (CHECK_FLAG(path->flags, BGP_PATH_VALID))
- bgp_evpn_import_route(bgp_path, afi, safi, p,
- path);
- else
- bgp_evpn_unimport_route(bgp_path, afi, safi, p,
- path);
+ path_valid = !!CHECK_FLAG(path->flags, BGP_PATH_VALID);
+ if (path_valid != bnc_is_valid_nexthop) {
+ if (path_valid) {
+ /* No longer valid, clear flag; also for EVPN
+ * routes, unimport from VRFs if needed.
+ */
+ bgp_aggregate_decrement(bgp_path, p, path, afi,
+ safi);
+ bgp_path_info_unset_flag(rn, path,
+ BGP_PATH_VALID);
+ if (safi == SAFI_EVPN &&
+ bgp_evpn_is_prefix_nht_supported(&rn->p))
+ bgp_evpn_unimport_route(bgp_path,
+ afi, safi, &rn->p, path);
+ } else {
+ /* Path becomes valid, set flag; also for EVPN
+ * routes, import from VRFs if needed.
+ */
+ bgp_path_info_set_flag(rn, path,
+ BGP_PATH_VALID);
+ bgp_aggregate_increment(bgp_path, p, path, afi,
+ safi);
+ if (safi == SAFI_EVPN &&
+ bgp_evpn_is_prefix_nht_supported(&rn->p))
+ bgp_evpn_import_route(bgp_path,
+ afi, safi, &rn->p, path);
+ }
}
bgp_process(bgp_path, rn, afi, safi);
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 78f077eaca..32489459cb 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -4706,8 +4706,9 @@ static void bgp_cleanup_table(struct bgp *bgp, struct bgp_table *table,
if (bgp_fibupd_safi(safi))
bgp_zebra_withdraw(p, pi, bgp, safi);
- bgp_path_info_reap(rn, pi);
}
+
+ bgp_path_info_reap(rn, pi);
}
}
@@ -10567,8 +10568,8 @@ DEFUN(show_ip_bgp_statistics_all, show_ip_bgp_statistics_all_cmd,
{
bool uj = use_json(argc, argv);
struct bgp *bgp = NULL;
- safi_t safi;
- afi_t afi;
+ safi_t safi = SAFI_UNICAST;
+ afi_t afi = AFI_IP6;
int idx = 0;
struct json_object *json_all = NULL;
struct json_object *json_afi_safi = NULL;
@@ -10626,8 +10627,8 @@ DEFUN (show_ip_bgp_l2vpn_evpn_statistics,
"BGP RIB advertisement statistics\n"
JSON_STR)
{
- afi_t afi;
- safi_t safi;
+ afi_t afi = AFI_IP6;
+ safi_t safi = SAFI_UNICAST;
struct bgp *bgp = NULL;
int idx = 0, ret;
bool uj = use_json(argc, argv);
@@ -10666,8 +10667,8 @@ DEFUN(show_ip_bgp_afi_safi_statistics, show_ip_bgp_afi_safi_statistics_cmd,
BGP_SAFI_WITH_LABEL_HELP_STR
"BGP RIB advertisement statistics\n" JSON_STR)
{
- afi_t afi;
- safi_t safi;
+ afi_t afi = AFI_IP6;
+ safi_t safi = SAFI_UNICAST;
struct bgp *bgp = NULL;
int idx = 0, ret;
bool uj = use_json(argc, argv);
@@ -13431,6 +13432,12 @@ void bgp_route_init(void)
install_element(BGP_IPV4M_NODE, &no_aggregate_address_mask_cmd);
/* IPv4 labeled-unicast configuration. */
+ install_element(BGP_IPV4L_NODE, &bgp_network_cmd);
+ install_element(BGP_IPV4L_NODE, &aggregate_address_cmd);
+ install_element(BGP_IPV4L_NODE, &aggregate_address_mask_cmd);
+ install_element(BGP_IPV4L_NODE, &no_aggregate_address_cmd);
+ install_element(BGP_IPV4L_NODE, &no_aggregate_address_mask_cmd);
+
install_element(VIEW_NODE, &show_ip_bgp_instance_all_cmd);
install_element(VIEW_NODE, &show_ip_bgp_cmd);
install_element(VIEW_NODE, &show_ip_bgp_afi_safi_statistics_cmd);
@@ -13477,6 +13484,11 @@ void bgp_route_init(void)
install_element(BGP_IPV6M_NODE, &ipv6_bgp_network_cmd);
+ /* IPv6 labeled unicast address family. */
+ install_element(BGP_IPV6L_NODE, &ipv6_bgp_network_cmd);
+ install_element(BGP_IPV6L_NODE, &ipv6_aggregate_address_cmd);
+ install_element(BGP_IPV6L_NODE, &no_ipv6_aggregate_address_cmd);
+
install_element(BGP_NODE, &bgp_distance_cmd);
install_element(BGP_NODE, &no_bgp_distance_cmd);
install_element(BGP_NODE, &bgp_distance_source_cmd);
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 0f09369860..e16030d82d 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -2987,8 +2987,7 @@ DEFUN (no_bgp_bestpath_med,
/* "bgp bestpath bandwidth" configuration. */
DEFPY (bgp_bestpath_bw,
bgp_bestpath_bw_cmd,
- "[no$no] bgp bestpath bandwidth [<ignore|skip-missing|default-weight-for-missing>$bw_cfg]",
- NO_STR
+ "bgp bestpath bandwidth <ignore|skip-missing|default-weight-for-missing>$bw_cfg",
"BGP specific commands\n"
"Change the default bestpath selection\n"
"Link Bandwidth attribute\n"
@@ -3000,22 +2999,18 @@ DEFPY (bgp_bestpath_bw,
afi_t afi;
safi_t safi;
- if (no) {
- bgp->lb_handling = BGP_LINK_BW_ECMP;
- } else {
- if (!bw_cfg) {
- vty_out(vty, "%% Bandwidth configuration must be specified\n");
- return CMD_ERR_INCOMPLETE;
- }
- if (!strcmp(bw_cfg, "ignore"))
- bgp->lb_handling = BGP_LINK_BW_IGNORE_BW;
- else if (!strcmp(bw_cfg, "skip-missing"))
- bgp->lb_handling = BGP_LINK_BW_SKIP_MISSING;
- else if (!strcmp(bw_cfg, "default-weight-for-missing"))
- bgp->lb_handling = BGP_LINK_BW_DEFWT_4_MISSING;
- else
- return CMD_ERR_NO_MATCH;
+ if (!bw_cfg) {
+ vty_out(vty, "%% Bandwidth configuration must be specified\n");
+ return CMD_ERR_INCOMPLETE;
}
+ if (!strcmp(bw_cfg, "ignore"))
+ bgp->lb_handling = BGP_LINK_BW_IGNORE_BW;
+ else if (!strcmp(bw_cfg, "skip-missing"))
+ bgp->lb_handling = BGP_LINK_BW_SKIP_MISSING;
+ else if (!strcmp(bw_cfg, "default-weight-for-missing"))
+ bgp->lb_handling = BGP_LINK_BW_DEFWT_4_MISSING;
+ else
+ return CMD_ERR_NO_MATCH;
/* This config is used in route install, so redo that. */
FOREACH_AFI_SAFI (afi, safi) {
@@ -3027,6 +3022,32 @@ DEFPY (bgp_bestpath_bw,
return CMD_SUCCESS;
}
+DEFPY (no_bgp_bestpath_bw,
+ no_bgp_bestpath_bw_cmd,
+ "no bgp bestpath bandwidth [<ignore|skip-missing|default-weight-for-missing>$bw_cfg]",
+ NO_STR
+ "BGP specific commands\n"
+ "Change the default bestpath selection\n"
+ "Link Bandwidth attribute\n"
+ "Ignore link bandwidth (i.e., do regular ECMP, not weighted)\n"
+ "Ignore paths without link bandwidth for ECMP (if other paths have it)\n"
+ "Assign a low default weight (value 1) to paths not having link bandwidth\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ afi_t afi;
+ safi_t safi;
+
+ bgp->lb_handling = BGP_LINK_BW_ECMP;
+
+ /* This config is used in route install, so redo that. */
+ FOREACH_AFI_SAFI (afi, safi) {
+ if (!bgp_fibupd_safi(safi))
+ continue;
+ bgp_zebra_announce_table(bgp, afi, safi);
+ }
+ return CMD_SUCCESS;
+}
+
/* "no bgp default ipv4-unicast". */
DEFUN (no_bgp_default_ipv4_unicast,
no_bgp_default_ipv4_unicast_cmd,
@@ -9066,7 +9087,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi,
}
}
- paf = peer_af_find(peer, afi, pfx_rcd_safi);
+ paf = peer_af_find(peer, afi, safi);
filter = &peer->filter[afi][safi];
count++;
@@ -15757,6 +15778,7 @@ void bgp_vty_init(void)
/* "bgp bestpath bandwidth" commands */
install_element(BGP_NODE, &bgp_bestpath_bw_cmd);
+ install_element(BGP_NODE, &no_bgp_bestpath_bw_cmd);
/* "no bgp default ipv4-unicast" commands. */
install_element(BGP_NODE, &no_bgp_default_ipv4_unicast_cmd);
@@ -16005,6 +16027,8 @@ void bgp_vty_init(void)
install_element(BGP_VPNV6_NODE, &neighbor_nexthop_self_all_hidden_cmd);
install_element(BGP_VPNV6_NODE,
&no_neighbor_nexthop_self_all_hidden_cmd);
+ install_element(BGP_EVPN_NODE, &neighbor_nexthop_self_force_cmd);
+ install_element(BGP_EVPN_NODE, &no_neighbor_nexthop_self_force_cmd);
/* "neighbor as-override" commands. */
install_element(BGP_NODE, &neighbor_as_override_hidden_cmd);
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index cca3f4aaa3..b7c255f16f 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -1143,7 +1143,8 @@ static bool update_ipv6nh_for_route_install(int nh_othervrf, struct bgp *nh_bgp,
api_nh->ifindex = 0;
}
}
- api_nh->gate.ipv6 = *nexthop;
+ if (nexthop)
+ api_nh->gate.ipv6 = *nexthop;
return true;
}
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index cf6335d373..faee7dad4a 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -1227,10 +1227,6 @@ struct peer *peer_new(struct bgp *bgp)
peer->addpath_type[afi][safi] = BGP_ADDPATH_NONE;
}
- /* set nexthop-unchanged for l2vpn evpn by default */
- SET_FLAG(peer->af_flags[AFI_L2VPN][SAFI_EVPN],
- PEER_FLAG_NEXTHOP_UNCHANGED);
-
SET_FLAG(peer->sflags, PEER_STATUS_CAPABILITY_OPEN);
/* Initialize per peer bgp GR FSM */
diff --git a/configure.ac b/configure.ac
index e1e23e224d..d4c652c6e5 100755
--- a/configure.ac
+++ b/configure.ac
@@ -7,7 +7,7 @@
##
AC_PREREQ([2.60])
-AC_INIT([frr], [7.4-dev], [https://github.com/frrouting/frr/issues])
+AC_INIT([frr], [7.5-dev], [https://github.com/frrouting/frr/issues])
PACKAGE_URL="https://frrouting.org/"
AC_SUBST([PACKAGE_URL])
PACKAGE_FULLNAME="FRRouting"
@@ -813,6 +813,7 @@ AC_SUBST([enable_vty_group])
enable_configfile_mask=${enable_configfile_mask:-0600}
AC_DEFINE_UNQUOTED([CONFIGFILE_MASK], [${enable_configfile_mask}], [Mask for config files])
+AC_SUBST([enable_configfile_mask])
enable_logfile_mask=${enable_logfile_mask:-0600}
AC_DEFINE_UNQUOTED([LOGFILE_MASK], [${enable_logfile_mask}], [Mask for log files])
diff --git a/doc/developer/lists.rst b/doc/developer/lists.rst
index 853c65ddf3..9355141aa4 100644
--- a/doc/developer/lists.rst
+++ b/doc/developer/lists.rst
@@ -105,7 +105,8 @@ Functions provided:
+====================================+======+======+======+=========+============+
| _init, _fini | yes | yes | yes | yes | yes |
+------------------------------------+------+------+------+---------+------------+
-| _first, _next, _next_safe | yes | yes | yes | yes | yes |
+| _first, _next, _next_safe, | yes | yes | yes | yes | yes |
+| _const_first, _const_next | | | | | |
+------------------------------------+------+------+------+---------+------------+
| _add_head, _add_tail, _add_after | yes | -- | -- | -- | -- |
+------------------------------------+------+------+------+---------+------------+
@@ -113,9 +114,10 @@ Functions provided:
+------------------------------------+------+------+------+---------+------------+
| _del, _pop | yes | yes | yes | yes | yes |
+------------------------------------+------+------+------+---------+------------+
-| _find | -- | -- | yes | yes | -- |
+| _find, _const_find | -- | -- | yes | yes | -- |
+------------------------------------+------+------+------+---------+------------+
-| _find_lt, _find_gteq | -- | -- | -- | yes | yes |
+| _find_lt, _find_gteq, | -- | -- | -- | yes | yes |
+| _const_find_lt, _const_find_gteq | | | | | |
+------------------------------------+------+------+------+---------+------------+
| use with frr_each() macros | yes | yes | yes | yes | yes |
+------------------------------------+------+------+------+---------+------------+
@@ -226,6 +228,10 @@ The following iteration macros work across all data structures:
resume iteration after breaking out of the loop by keeping the ``from``
value persistent and reusing it for the next loop.
+To iterate over ``const`` pointers, add ``_const`` to the name of the
+datastructure (``Z`` above), e.g. ``frr_each (mylist, head, item)`` becomes
+``frr_each (mylist_const, head, item)``.
+
Common API
----------
@@ -248,7 +254,7 @@ The following documentation assumes that a list has been defined using
This function may ``assert()`` if the list is not empty.
-.. c:function:: size_t Z_count(struct Z_head *)
+.. c:function:: size_t Z_count(const struct Z_head *)
Returns the number of items in a structure. All structures store a
counter in their `Z_head` so that calling this function completes
@@ -260,6 +266,7 @@ The following documentation assumes that a list has been defined using
outdated by the time this function returns and can therefore only be
used as an estimate.
+.. c:function:: const itemtype *Z_const_first(const struct Z_head *)
.. c:function:: itemtype *Z_first(struct Z_head *)
Returns the first item in the structure, or ``NULL`` if the structure is
@@ -288,6 +295,7 @@ The following documentation assumes that a list has been defined using
affected by the "modification while iterating" problem. To remove
all items from a hash table, use the loop demonstrated above.
+.. c:function:: const itemtype *Z_next(const struct Z_head *, const itemtype *prev)
.. c:function:: itemtype *Z_next(struct Z_head *, itemtype *prev)
Return the item that follows after ``prev``, or ``NULL`` if ``prev`` is
@@ -421,6 +429,7 @@ sorted lists can be searched for a value.
For ``_NONUNIQ`` lists, this function always returns NULL since ``item``
can always be successfully added to the list.
+.. c:function:: const itemtype *Z_find(const struct Z_head *, const itemtype *ref)
.. c:function:: itemtype *Z_find(struct Z_head *, const itemtype *ref)
Search the list for an item that compares equal to ``ref``. If no equal
@@ -442,11 +451,13 @@ sorted lists can be searched for a value.
containing non-unique items, more than one item may compare as equal to
the item that is searched for.
+.. c:function:: const itemtype *Z_find_gteq(const struct Z_head *, const itemtype *ref)
.. c:function:: itemtype *Z_find_gteq(struct Z_head *, const itemtype *ref)
Search the list for an item that compares greater or equal to
``ref``. See :c:func:`Z_find()` above.
+.. c:function:: const itemtype *Z_find_lt(const struct Z_head *, const itemtype *ref)
.. c:function:: itemtype *Z_find_lt(struct Z_head *, const itemtype *ref)
Search the list for an item that compares less than
@@ -616,21 +627,9 @@ Head removal (pop) and deallocation:
FAQ
---
-Why is the list head not ``const`` in the list APIs?
- The semantics that a ``const`` list head would imply are not obvious. It
- could mean any of the following:
-
- * the list just shouldn't be allocated/deallocated, but may be modified.
- This doesn't actually work since the list head needs to be modified for
- inserting or deleting items.
-
- * the list shouldn't be modified, but items can. This may make sense for
- iterating, but it's not exactly consistent - an item might be on more
- than one list, does it apply to all of them? If not, which one?
-
- * neither the list nor the items should be modified. This is consistent,
- but hard to do without creating a ``const`` copy of every single list
- function. Ease of use trumps this.
+What are the semantics of ``const`` in the list APIs?
+ ``const`` pointers to list heads and/or items are interpreted to mean that
+ both the list itself as well as the data items are read-only.
Why is there no "is this item on a/the list" test?
It's slow for several of the data structures, and the work of adding it
diff --git a/doc/user/bfd.rst b/doc/user/bfd.rst
index 32397d1303..40c2247b5b 100644
--- a/doc/user/bfd.rst
+++ b/doc/user/bfd.rst
@@ -84,6 +84,20 @@ BFDd Commands
Stops and removes the selected peer.
+
+.. index:: profile WORD
+.. clicmd:: profile WORD
+
+ Creates a peer profile that can be configured in multiple peers.
+
+
+.. index:: no profile WORD
+.. clicmd:: no profile WORD
+
+ Deletes a peer profile. Any peer using the profile will have their
+ configurations reset to the default values.
+
+
.. index:: show bfd [vrf NAME] peers [json]
.. clicmd:: show bfd [vrf NAME] peers [json]
@@ -101,8 +115,10 @@ BFDd Commands
.. _bfd-peer-config:
-Peer Configurations
--------------------
+Peer / Profile Configuration
+----------------------------
+
+BFD peers and profiles share the same BFD session configuration commands.
.. index:: detect-multiplier (2-255)
.. clicmd:: detect-multiplier (2-255)
@@ -154,6 +170,10 @@ Peer Configurations
Enables or disables the peer. When the peer is disabled an
'administrative down' message is sent to the remote peer.
+
+BFD Peer Specific Commands
+--------------------------
+
.. index:: label WORD
.. clicmd:: label WORD
@@ -161,6 +181,21 @@ Peer Configurations
later on other daemons to refer to a specific peer.
+.. index:: profile BFDPROF
+.. clicmd:: profile BFDPROF
+
+ Configure peer to use the profile configurations.
+
+ Notes:
+
+ - Profile configurations can be overriden on a peer basis by specifying
+ new parameters in peer configuration node.
+ - Non existing profiles can be configured and they will only be applied
+ once they start to exist.
+ - If the profile gets updated the new configuration will be applied to all
+ peers with the profile without interruptions.
+
+
.. _bfd-bgp-peer-config:
BGP BFD Configuration
@@ -292,6 +327,24 @@ Here are the available peer configurations:
::
bfd
+ ! Configure a fast profile
+ profile fast
+ receive-interval 150
+ transmit-interval 150
+ !
+
+ ! Configure peer with fast profile
+ peer 192.168.0.6
+ profile fast
+ no shutdown
+ !
+
+ ! Configure peer with fast profile and override receive speed.
+ peer 192.168.0.7
+ profile fast
+ receive-interval 500
+ no shutdown
+ !
! configure a peer on an specific interface
peer 192.168.0.1 interface eth0
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index cb343e8dad..7c86cac11c 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -971,7 +971,7 @@ Route Aggregation-IPv4 Address Family
.. clicmd:: aggregate-address A.B.C.D/M summary-only
This command specifies an aggregate address. Aggregated routes will
- not be announce.
+ not be announced.
.. index:: no aggregate-address A.B.C.D/M
.. clicmd:: no aggregate-address A.B.C.D/M
@@ -1023,7 +1023,7 @@ Route Aggregation-IPv6 Address Family
.. clicmd:: aggregate-address X:X::X:X/M summary-only
This command specifies an aggregate address. Aggregated routes will
- not be announce.
+ not be announced.
.. index:: no aggregate-address X:X::X:X/M
.. clicmd:: no aggregate-address X:X::X:X/M
@@ -1776,7 +1776,7 @@ In :ref:`route-map` we can match on or set the BGP communities attribute. Using
this feature network operator can implement their network policy based on BGP
communities attribute.
-The ollowing commands can be used in route maps:
+The following commands can be used in route maps:
.. index:: match community WORD exact-match [exact-match]
.. clicmd:: match community WORD exact-match [exact-match]
@@ -2391,6 +2391,27 @@ the same behavior of using same next-hop and RMAC values.
Enables or disables advertise-pip feature, specifiy system-IP and/or system-MAC
parameters.
+Support with VRF network namespace backend
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+It is possible to separate overlay networks contained in VXLAN interfaces from
+underlay networks by using VRFs. VRF-lite and VRF-netns backends can be used for
+that. In the latter case, this is necessary to set both bridge and vxlan interface
+on the same network namespace, as below example illustrates:
+
+.. code-block:: shell
+
+ # linux shell
+ ip netns add vrf1
+ ip link add name vxlan101 type vxlan id 101 dstport 4789 dev eth0 local 10.1.1.1
+ ip link set dev vxlan101 netns vrf1
+ ip netns exec vrf1 ip link set dev lo up
+ ip netns exec vrf1 brctl addbr bridge101
+ ip netns exec vrf1 brctl addif bridge101 vxlan101
+
+This makes possible to separate not only layer 3 networks like VRF-lite networks.
+Also, VRF netns based make possible to separate layer 2 networks on separate VRF
+instances.
+
.. _bgp-cisco-compatibility:
Cisco Compatibility
@@ -2840,8 +2861,8 @@ Displaying Routes by AS Path
Displaying Update Group Information
-----------------------------------
-..index:: show bgp update-groups SUBGROUP-ID [advertise-queue|advertised-routes|packet-queue]
-..clicmd:: show bgp update-groups [advertise-queue|advertised-routes|packet-queue]
+.. index:: show bgp update-groups SUBGROUP-ID [advertise-queue|advertised-routes|packet-queue]
+.. clicmd:: show bgp update-groups [advertise-queue|advertised-routes|packet-queue]
Display Information about each individual update-group being used.
If SUBGROUP-ID is specified only display about that particular group. If
@@ -2850,8 +2871,8 @@ Displaying Update Group Information
the list of routes we have sent to the peers in the update-group and
packet-queue specifies the list of packets in the queue to be sent.
-..index:: show bgp update-groups statistics
-..clicmd:: show bgp update-groups statistics
+.. index:: show bgp update-groups statistics
+.. clicmd:: show bgp update-groups statistics
Display Information about update-group events in FRR.
@@ -3041,8 +3062,8 @@ certainly contains silly mistakes, if not serious flaws.
ip prefix-list pl-peer2-network permit 192.168.2.0/24
ip prefix-list pl-peer2-network permit 172.16.1/24
!
- ip as-path access-list asp-own-as permit ^$
- ip as-path access-list asp-own-as permit _64512_
+ bgp as-path access-list asp-own-as permit ^$
+ bgp as-path access-list asp-own-as permit _64512_
!
! #################################################################
! Match communities we provide actions for, on routes receives from
diff --git a/doc/user/frr-reload.rst b/doc/user/frr-reload.rst
new file mode 100644
index 0000000000..9348b876a4
--- /dev/null
+++ b/doc/user/frr-reload.rst
@@ -0,0 +1,12 @@
+.. _frr-reload:
+
+
+The frr-reload.py script
+========================
+
+
+
+Options
+-------
+
+There are several options that control the behavior of ``frr-reload``.
diff --git a/doc/user/index.rst b/doc/user/index.rst
index 416c51f13b..7bb86e563b 100644
--- a/doc/user/index.rst
+++ b/doc/user/index.rst
@@ -71,6 +71,7 @@ Appendix
bugs
packet-dumps
glossary
+ frr-reload
################
Copyright notice
diff --git a/doc/user/isisd.rst b/doc/user/isisd.rst
index 9a0a0afb0c..dc598ea5bf 100644
--- a/doc/user/isisd.rst
+++ b/doc/user/isisd.rst
@@ -470,6 +470,57 @@ Traffic Engineering
.. _debugging-isis:
+Segment Routing
+===============
+
+This is an EXPERIMENTAL support of Segment Routing as per RFC8667
+for MPLS dataplane. It supports IPv4, IPv6 and ECMP and has been
+tested against Cisco & Juniper routers.
+
+Known limitations:
+ - No support for level redistribution (L1 to L2 or L2 to L1)
+ - No support for binding SID
+ - No support for SRMS
+ - No support for SRLB
+ - Only one SRGB and default SPF Algorithm is supported
+
+.. index:: [no] segment-routing on
+.. clicmd:: [no] segment-routing on
+
+ Enable Segment Routing.
+
+.. index:: [no] segment-routing global-block (0-1048575) (0-1048575)
+.. clicmd:: [no] segment-routing global-block (0-1048575) (0-1048575)
+
+ Set the Segment Routing Global Block i.e. the label range used by MPLS
+ to store label in the MPLS FIB.
+
+.. index:: [no] segment-routing node-msd (1-16)
+.. clicmd:: [no] segment-routing node-msd (1-16)
+
+ Set the Maximum Stack Depth supported by the router. The value depend of the
+ MPLS dataplane. E.g. for Linux kernel, since version 4.13 the maximum value
+ is 32.
+
+.. index:: [no] segment-routing prefix <A.B.C.D/M|X:X::X:X/M> <absolute (16-1048575)|index (0-65535)> [no-php-flag|explicit-null]
+.. clicmd:: [no] segment-routing prefix <A.B.C.D/M|X:X::X:X/M> <absolute (16-1048575)|index (0-65535) [no-php-flag|explicit-null]
+
+ Set the Segment Routing index or absolute label value for the specified
+ prefix. The 'no-php-flag' means NO Penultimate Hop Popping that allows SR
+ node to request to its neighbor to not pop the label. The 'explicit-null'
+ flag allows SR node to request to its neighbor to send IP packet with the
+ EXPLICIT-NULL label.
+
+.. index:: show isis segment-routing prefix-sids
+.. clicmd:: show isis segment-routing prefix-sids
+
+ Show detailed information about all learned Segment Routing Prefix-SIDs.
+
+.. index:: show isis segment-routing nodes
+.. clicmd:: show isis segment-routing nodes
+
+ Show detailed information about all learned Segment Routing Nodes.
+
Debugging ISIS
==============
@@ -566,6 +617,14 @@ Debugging ISIS
Update related packets.
+.. index:: debug isis sr-events
+.. clicmd:: debug isis sr-events
+
+.. index:: no debug isis sr-events
+.. clicmd:: no debug isis sr-events
+
+ IS-IS Segment Routing events.
+
.. index:: show debugging isis
.. clicmd:: show debugging isis
@@ -655,3 +714,32 @@ Then the :file:`isisd.conf` itself:
mpls-te router-address 10.1.1.1
!
line vty
+
+A Segment Routing configuration, with IPv4, IPv6, SRGB and MSD configuration.
+
+.. code-block:: frr
+
+ hostname HOSTNAME
+ password PASSWORD
+ log file /var/log/isisd.log
+ !
+ !
+ interface eth0
+ ip router isis SR
+ isis network point-to-point
+ !
+ interface eth1
+ ip router isis SR
+ !
+ !
+ router isis SR
+ net 49.0000.0000.0000.0001.00
+ is-type level-1
+ topology ipv6-unicast
+ lsp-gen-interval 2
+ segment-routing on
+ segment-routing node-msd 8
+ segment-routing prefix 10.1.1.1/32 index 100 explicit-null
+ segment-routing prefix 2001:db8:1000::1/128 index 101 explicit-null
+ !
+
diff --git a/doc/user/ospf_fundamentals.rst b/doc/user/ospf_fundamentals.rst
index da348b02d2..b0eb018107 100644
--- a/doc/user/ospf_fundamentals.rst
+++ b/doc/user/ospf_fundamentals.rst
@@ -83,8 +83,8 @@ sharing a link, for example:
- DR/BDR election results.
- Any optional capabilities supported by each router.
-The Hello protocol is comparatively trivial and will not be explored in greater
-detail than here.
+The Hello protocol is comparatively trivial and will not be explored in more
+detail.
.. index:: OSPF LSA overview
.. _ospf-lsas:
@@ -233,7 +233,7 @@ called `intra-area routes`.
Cost
The output cost of that interface, scaled inversely to some commonly known
- reference value, :clicmd:`auto-cost reference-bandwidth (1-4294967`.
+ reference value, :clicmd:`auto-cost reference-bandwidth (1-4294967)`.
Link Type
Transit Network
diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst
index 75768269fe..16eaf3be2a 100644
--- a/doc/user/ospfd.rst
+++ b/doc/user/ospfd.rst
@@ -177,8 +177,8 @@ To start OSPF process you have to specify the OSPF router.
OSPF (:ref:`redistribute-routes-to-ospf`). This is the only way to
advertise non-OSPF links into stub areas.
-.. index:: timers throttle spf DELAY INITIAL-HOLDTIME MAX-HOLDTIME
-.. clicmd:: timers throttle spf DELAY INITIAL-HOLDTIME MAX-HOLDTIME
+.. index:: timers throttle spf (0-600000) (0-600000) (0-600000)
+.. clicmd:: timers throttle spf (0-600000) (0-600000) (0-600000)
.. index:: no timers throttle spf
.. clicmd:: no timers throttle spf
@@ -693,11 +693,11 @@ Interfaces
retransmitting Database Description and Link State Request packets. The
default value is 5 seconds.
-.. index:: ip ospf transmit-delay
-.. clicmd:: ip ospf transmit-delay
+.. index:: ip ospf transmit-delay (1-65535) [A.B.C.D]
+.. clicmd:: ip ospf transmit-delay (1-65535) [A.B.C.D]
-.. index:: no ip ospf transmit-delay
-.. clicmd:: no ip ospf transmit-delay
+.. index:: no ip ospf transmit-delay [(1-65535)] [A.B.C.D]
+.. clicmd:: no ip ospf transmit-delay [(1-65535)] [A.B.C.D]
Set number of seconds for InfTransDelay value. LSAs' age should be
incremented by this value when transmitting. The default value is 1 second.
diff --git a/doc/user/overview.rst b/doc/user/overview.rst
index cf8cc44097..64a54d9a7d 100644
--- a/doc/user/overview.rst
+++ b/doc/user/overview.rst
@@ -395,7 +395,14 @@ MPLS
- :rfc:`7552`
:t:`Updates to LDP for IPv6, R. Asati, C. Pignataro, K. Raza, V. Manral, and R. Papneja. June 2015.`
+VRRP
+----
+- :rfc:`3768`
+ :t:`Virtual Router Redundancy Protocol (VRRP). R. Hinden. April 2004.`
+- :rfc:`5798`
+ :t:`Virtual Router Redundancy Protocol (VRRP) Version 3 for IPv4 and IPv6. S. Nadas. June 2000.`
+
SNMP
----
diff --git a/doc/user/pim.rst b/doc/user/pim.rst
index 2944e0b705..4e04a0117d 100644
--- a/doc/user/pim.rst
+++ b/doc/user/pim.rst
@@ -536,6 +536,16 @@ cause great confusion.
Display multicast traceroute towards source, optionally for particular group.
+.. index:: show ip multicast count [vrf NAME] [json]
+.. clicmd:: show ip multicast count [vrf NAME] [json]
+
+ Display multicast data packets count per interface for a vrf.
+
+.. index:: show ip multicast count vrf all [json]
+.. clicmd:: show ip multicast count vrf all [json]
+
+ Display multicast data packets count per interface for all vrf.
+
PIM Debug Commands
==================
diff --git a/doc/user/setup.rst b/doc/user/setup.rst
index f60a66b9fd..6a52cf26c4 100644
--- a/doc/user/setup.rst
+++ b/doc/user/setup.rst
@@ -218,6 +218,9 @@ individual or unified daemon configuration files.
systemctl reload frr
+See :ref:`FRR-RELOAD <frr-reload>` for more about the `frr-reload.py` script.
+
+
Starting a new daemon
^^^^^^^^^^^^^^^^^^^^^
diff --git a/doc/user/subdir.am b/doc/user/subdir.am
index 0b64232f3d..eb7b7ced52 100644
--- a/doc/user/subdir.am
+++ b/doc/user/subdir.am
@@ -13,6 +13,7 @@ user_RSTFILES = \
doc/user/eigrpd.rst \
doc/user/fabricd.rst \
doc/user/filter.rst \
+ doc/user/frr-reload.rst \
doc/user/glossary.rst \
doc/user/index.rst \
doc/user/installation.rst \
diff --git a/doc/user/wecmp_linkbw.rst b/doc/user/wecmp_linkbw.rst
index 0d2fe9d756..8176aaffcb 100644
--- a/doc/user/wecmp_linkbw.rst
+++ b/doc/user/wecmp_linkbw.rst
@@ -14,7 +14,7 @@ across these next hops. In practice, flow-based hashing is used so that
all traffic associated with a particular flow uses the same next hop,
and by extension, the same path across the network.
-Weigted ECMP using BGP link bandwidth introduces support for network-wide
+Weighted ECMP using BGP link bandwidth introduces support for network-wide
unequal cost multipathing (UCMP) to an IP destination. The unequal cost
load balancing is implemented by the forwarding plane based on the weights
associated with the next hops of the IP prefix. These weights are computed
diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst
index 9dfd08f733..f105bd72bc 100644
--- a/doc/user/zebra.rst
+++ b/doc/user/zebra.rst
@@ -708,6 +708,24 @@ that sets the preferred source address, and applies the route-map to all
ip protocol rip route-map RM1
+IPv6 example for OSPFv3.
+
+.. code-block:: frr
+
+ ipv6 prefix-list ANY seq 10 permit any
+ route-map RM6 permit 10
+ match ipv6 address prefix-list ANY
+ set src 2001:db8:425:1000::3
+
+ ipv6 protocol ospf6 route-map RM6
+
+
+.. note::
+
+ For both IPv4 and IPv6, the IP address has to exist at the point the
+ route-map is created. Be wary of race conditions if the interface is
+ not created at startup. On Debian, FRR might start before ifupdown
+ completes. Consider a reboot test.
.. _zebra-fib-push-interface:
@@ -852,6 +870,20 @@ FPM Commands
will not attempt to connect to it anymore.
+.. index:: fpm use-next-hop-groups
+.. clicmd:: fpm use-next-hop-groups
+
+ Use the new netlink messages ``RTM_NEWNEXTHOP`` / ``RTM_DELNEXTHOP`` to
+ group repeated route next hop information.
+
+
+.. index:: no fpm use-next-hop-groups
+.. clicmd:: no fpm use-next-hop-groups
+
+ Use the old known FPM behavior of including next hop information in the
+ route (e.g. ``RTM_NEWROUTE``) messages.
+
+
.. index:: show fpm counters [json]
.. clicmd:: show fpm counters [json]
@@ -967,15 +999,15 @@ zebra Terminal Mode Commands
.. index:: show ip protocol
.. clicmd:: show ip protocol
-.. index:: show ipforward
-.. clicmd:: show ipforward
+.. index:: show ip forward
+.. clicmd:: show ip forward
Display whether the host's IP forwarding function is enabled or not.
Almost any UNIX kernel can be configured with IP forwarding disabled.
If so, the box can't work as a router.
-.. index:: show ipv6forward
-.. clicmd:: show ipv6forward
+.. index:: show ipv6 forward
+.. clicmd:: show ipv6 forward
Display whether the host's IP v6 forwarding is enabled or not.
diff --git a/include/linux/net_namespace.h b/include/linux/net_namespace.h
index 0187c74d88..0ed9dd61d3 100644
--- a/include/linux/net_namespace.h
+++ b/include/linux/net_namespace.h
@@ -16,6 +16,7 @@ enum {
NETNSA_NSID,
NETNSA_PID,
NETNSA_FD,
+ NETNSA_TARGET_NSID,
__NETNSA_MAX,
};
diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c
index 4e0ee4448b..acfe3e2e1f 100644
--- a/isisd/isis_adjacency.c
+++ b/isisd/isis_adjacency.c
@@ -93,6 +93,7 @@ struct isis_adjacency *isis_new_adj(const uint8_t *id, const uint8_t *snpa,
.last_dis_change = time(NULL);
}
}
+ adj->adj_sids = list_new();
return adj;
}
@@ -122,6 +123,44 @@ struct isis_adjacency *isis_adj_lookup_snpa(const uint8_t *ssnpa,
return NULL;
}
+bool isis_adj_exists(const struct isis_area *area, int level,
+ const uint8_t *sysid)
+{
+ struct isis_circuit *circuit;
+ struct listnode *node;
+
+ for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
+ struct isis_adjacency *adj;
+ struct listnode *anode;
+ struct list *adjdb;
+
+ switch (circuit->circ_type) {
+ case CIRCUIT_T_BROADCAST:
+ adjdb = circuit->u.bc.adjdb[level - 1];
+ if (!adjdb)
+ continue;
+
+ for (ALL_LIST_ELEMENTS_RO(adjdb, anode, adj)) {
+ if (!memcmp(adj->sysid, sysid, ISIS_SYS_ID_LEN))
+ return true;
+ }
+ break;
+ case CIRCUIT_T_P2P:
+ adj = circuit->u.p2p.neighbor;
+ if (!adj)
+ break;
+
+ if (!memcmp(adj->sysid, sysid, ISIS_SYS_ID_LEN))
+ return true;
+ break;
+ default:
+ break;
+ }
+ }
+
+ return false;
+}
+
DEFINE_HOOK(isis_adj_state_change_hook, (struct isis_adjacency *adj), (adj))
void isis_delete_adj(void *arg)
@@ -145,6 +184,7 @@ void isis_delete_adj(void *arg)
XFREE(MTYPE_ISIS_ADJACENCY_INFO, adj->ipv6_addresses);
adj_mt_finish(adj);
+ list_delete(&adj->adj_sids);
XFREE(MTYPE_ISIS_ADJACENCY, adj);
return;
@@ -441,6 +481,9 @@ void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty,
}
if (detail == ISIS_UI_LEVEL_DETAIL) {
+ struct sr_adjacency *sra;
+ struct listnode *anode;
+
level = adj->level;
vty_out(vty, "\n");
if (adj->circuit)
@@ -529,6 +572,31 @@ void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty,
vty_out(vty, " %s\n", buf);
}
}
+ for (ALL_LIST_ELEMENTS_RO(adj->adj_sids, anode, sra)) {
+ const char *adj_type;
+ const char *backup;
+ uint32_t sid;
+
+ switch (sra->adj->circuit->circ_type) {
+ case CIRCUIT_T_BROADCAST:
+ adj_type = "LAN Adjacency-SID";
+ sid = sra->u.ladj_sid->sid;
+ break;
+ case CIRCUIT_T_P2P:
+ adj_type = "Adjacency-SID";
+ sid = sra->u.adj_sid->sid;
+ break;
+ default:
+ continue;
+ }
+ backup = (sra->type == ISIS_SR_LAN_BACKUP) ? " (backup)"
+ : "";
+
+ vty_out(vty, " %s %s%s: %u\n",
+ (sra->nexthop.family == AF_INET) ? "IPv4"
+ : "IPv6",
+ adj_type, backup, sid);
+ }
vty_out(vty, "\n");
}
return;
diff --git a/isisd/isis_adjacency.h b/isisd/isis_adjacency.h
index 8f3d63c297..ec17446ade 100644
--- a/isisd/isis_adjacency.h
+++ b/isisd/isis_adjacency.h
@@ -69,6 +69,7 @@ struct isis_dis_record {
};
struct bfd_session;
+struct isis_area;
struct isis_adjacency {
uint8_t snpa[ETH_ALEN]; /* NeighbourSNPAAddress */
@@ -103,6 +104,7 @@ struct isis_adjacency {
uint16_t *mt_set; /* Topologies this adjacency is valid for */
unsigned int mt_count; /* Number of entries in mt_set */
struct bfd_session *bfd_session;
+ struct list *adj_sids; /* Segment Routing Adj-SIDs. */
};
struct isis_threeway_adj;
@@ -111,6 +113,8 @@ struct isis_adjacency *isis_adj_lookup(const uint8_t *sysid,
struct list *adjdb);
struct isis_adjacency *isis_adj_lookup_snpa(const uint8_t *ssnpa,
struct list *adjdb);
+bool isis_adj_exists(const struct isis_area *area, int level,
+ const uint8_t *sysid);
struct isis_adjacency *isis_new_adj(const uint8_t *id, const uint8_t *snpa,
int level, struct isis_circuit *circuit);
void isis_delete_adj(void *adj);
@@ -118,6 +122,10 @@ void isis_adj_process_threeway(struct isis_adjacency *adj,
struct isis_threeway_adj *tw_adj,
enum isis_adj_usage adj_usage);
DECLARE_HOOK(isis_adj_state_change_hook, (struct isis_adjacency *adj), (adj))
+DECLARE_HOOK(isis_adj_ip_enabled_hook,
+ (struct isis_adjacency *adj, int family), (adj, family))
+DECLARE_HOOK(isis_adj_ip_disabled_hook,
+ (struct isis_adjacency *adj, int family), (adj, family))
void isis_adj_state_change(struct isis_adjacency **adj,
enum isis_adj_state state, const char *reason);
void isis_adj_print(struct isis_adjacency *adj);
diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c
index 39118a2c86..1f76a3b2bb 100644
--- a/isisd/isis_circuit.c
+++ b/isisd/isis_circuit.c
@@ -1223,6 +1223,8 @@ struct isis_circuit *isis_circuit_create(struct isis_area *area,
if (circuit->state != C_STATE_CONF && circuit->state != C_STATE_UP)
return circuit;
isis_circuit_if_bind(circuit, ifp);
+ if (circuit->area->mta && circuit->area->mta->status)
+ isis_link_params_update(circuit, ifp);
return circuit;
}
diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c
index c12c7fa936..c421750a82 100644
--- a/isisd/isis_cli.c
+++ b/isisd/isis_cli.c
@@ -1356,6 +1356,215 @@ void cli_show_isis_mt_ipv6_dstsrc(struct vty *vty, struct lyd_node *dnode,
}
/*
+ * XPath: /frr-isisd:isis/instance/segment-routing/enabled
+ */
+DEFPY (isis_sr_enable,
+ isis_sr_enable_cmd,
+ "segment-routing on",
+ SR_STR
+ "Enable Segment Routing\n")
+{
+ nb_cli_enqueue_change(vty, "./segment-routing/enabled", NB_OP_MODIFY,
+ "true");
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY (no_isis_sr_enable,
+ no_isis_sr_enable_cmd,
+ "no segment-routing [on]",
+ NO_STR
+ SR_STR
+ "Disable Segment Routing\n")
+{
+ nb_cli_enqueue_change(vty, "./segment-routing/enabled", NB_OP_MODIFY,
+ "false");
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void cli_show_isis_sr_enabled(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ if (!yang_dnode_get_bool(dnode, NULL))
+ vty_out(vty, " no");
+
+ vty_out(vty, " segment-routing on\n");
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/segment-routing/srgb
+ */
+DEFPY (isis_sr_global_block_label_range,
+ isis_sr_global_block_label_range_cmd,
+ "segment-routing global-block (16-1048575)$lower_bound (16-1048575)$upper_bound",
+ SR_STR
+ "Segment Routing Global Block label range\n"
+ "The lower bound of SRGB (16-1048575)\n"
+ "The upper bound of SRGB (16-1048575)\n")
+{
+ nb_cli_enqueue_change(vty, "./segment-routing/srgb/lower-bound",
+ NB_OP_MODIFY, lower_bound_str);
+ nb_cli_enqueue_change(vty, "./segment-routing/srgb/upper-bound",
+ NB_OP_MODIFY, upper_bound_str);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY (no_isis_sr_global_block_label_range,
+ no_isis_sr_global_block_label_range_cmd,
+ "no segment-routing global-block [(0-1048575) (0-1048575)]",
+ NO_STR
+ SR_STR
+ "Segment Routing Global Block label range\n"
+ "The lower bound of SRGB (16-1048575)\n"
+ "The upper bound of SRGB (block size may not exceed 65535)\n")
+{
+ nb_cli_enqueue_change(vty, "./segment-routing/srgb/lower-bound",
+ NB_OP_MODIFY, NULL);
+ nb_cli_enqueue_change(vty, "./segment-routing/srgb/upper-bound",
+ NB_OP_MODIFY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void cli_show_isis_srgb(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ vty_out(vty, " segment-routing global-block %s %s\n",
+ yang_dnode_get_string(dnode, "./lower-bound"),
+ yang_dnode_get_string(dnode, "./upper-bound"));
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/segment-routing/msd/node-msd
+ */
+DEFPY (isis_sr_node_msd,
+ isis_sr_node_msd_cmd,
+ "segment-routing node-msd (1-16)$msd",
+ SR_STR
+ "Maximum Stack Depth for this router\n"
+ "Maximum number of label that can be stack (1-16)\n")
+{
+ nb_cli_enqueue_change(vty, "./segment-routing/msd/node-msd",
+ NB_OP_MODIFY, msd_str);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY (no_isis_sr_node_msd,
+ no_isis_sr_node_msd_cmd,
+ "no segment-routing node-msd [(1-16)]",
+ NO_STR
+ SR_STR
+ "Maximum Stack Depth for this router\n"
+ "Maximum number of label that can be stack (1-16)\n")
+{
+ nb_cli_enqueue_change(vty, "./segment-routing/msd/node-msd",
+ NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void cli_show_isis_node_msd(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ vty_out(vty, " segment-routing node-msd %s\n",
+ yang_dnode_get_string(dnode, NULL));
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/segment-routing/prefix-sid-map/prefix-sid
+ */
+DEFPY (isis_sr_prefix_sid,
+ isis_sr_prefix_sid_cmd,
+ "segment-routing prefix\
+ <A.B.C.D/M|X:X::X:X/M>$prefix\
+ <absolute$sid_type (16-1048575)$sid_value|index$sid_type (0-65535)$sid_value>\
+ [<no-php-flag|explicit-null>$lh_behavior]",
+ SR_STR
+ "Prefix SID\n"
+ "IPv4 Prefix\n"
+ "IPv6 Prefix\n"
+ "Specify the absolute value of Prefix Segement ID\n"
+ "The Prefix Segment ID value\n"
+ "Specify the index of Prefix Segement ID\n"
+ "The Prefix Segment ID index\n"
+ "Don't request Penultimate Hop Popping (PHP)\n"
+ "Upstream neighbor must replace prefix-sid with explicit null label\n")
+{
+ nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL);
+ nb_cli_enqueue_change(vty, "./sid-value-type", NB_OP_MODIFY, sid_type);
+ nb_cli_enqueue_change(vty, "./sid-value", NB_OP_MODIFY, sid_value_str);
+ if (lh_behavior) {
+ const char *value;
+
+ if (strmatch(lh_behavior, "no-php-flag"))
+ value = "no-php";
+ else
+ value = "explicit-null";
+
+ nb_cli_enqueue_change(vty, "./last-hop-behavior", NB_OP_MODIFY,
+ value);
+ } else
+ nb_cli_enqueue_change(vty, "./last-hop-behavior", NB_OP_MODIFY,
+ NULL);
+
+ return nb_cli_apply_changes(
+ vty, "./segment-routing/prefix-sid-map/prefix-sid[prefix='%s']",
+ prefix_str);
+}
+
+DEFPY (no_isis_sr_prefix_sid,
+ no_isis_sr_prefix_sid_cmd,
+ "no segment-routing prefix <A.B.C.D/M|X:X::X:X/M>$prefix\
+ [<absolute$sid_type (16-1048575)|index (0-65535)> [<no-php-flag|explicit-null>]]",
+ NO_STR
+ SR_STR
+ "Prefix SID\n"
+ "IPv4 Prefix\n"
+ "IPv6 Prefix\n"
+ "Specify the absolute value of Prefix Segement ID\n"
+ "The Prefix Segment ID value\n"
+ "Specify the index of Prefix Segement ID\n"
+ "The Prefix Segment ID index\n"
+ "Don't request Penultimate Hop Popping (PHP)\n"
+ "Upstream neighbor must replace prefix-sid with explicit null label\n")
+{
+ nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL);
+
+ return nb_cli_apply_changes(
+ vty, "./segment-routing/prefix-sid-map/prefix-sid[prefix='%s']",
+ prefix_str);
+}
+
+void cli_show_isis_prefix_sid(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults)
+{
+ const char *prefix;
+ const char *lh_behavior;
+ const char *sid_value_type;
+ const char *sid_value;
+
+ prefix = yang_dnode_get_string(dnode, "./prefix");
+ lh_behavior = yang_dnode_get_string(dnode, "./last-hop-behavior");
+ sid_value_type = yang_dnode_get_string(dnode, "./sid-value-type");
+ sid_value = yang_dnode_get_string(dnode, "./sid-value");
+
+ vty_out(vty, " segment-routing prefix %s", prefix);
+ if (strmatch(sid_value_type, "absolute"))
+ vty_out(vty, " absolute");
+ else
+ vty_out(vty, " index");
+ vty_out(vty, " %s", sid_value);
+ if (strmatch(lh_behavior, "no-php"))
+ vty_out(vty, " no-php-flag");
+ else if (strmatch(lh_behavior, "explicit-null"))
+ vty_out(vty, " explicit-null");
+ vty_out(vty, "\n");
+}
+
+/*
* XPath: /frr-interface:lib/interface/frr-isisd:isis/passive
*/
DEFPY(isis_passive, isis_passive_cmd, "[no] isis passive",
@@ -2095,6 +2304,15 @@ void isis_cli_init(void)
install_element(ISIS_NODE, &isis_topology_cmd);
+ install_element(ISIS_NODE, &isis_sr_enable_cmd);
+ install_element(ISIS_NODE, &no_isis_sr_enable_cmd);
+ install_element(ISIS_NODE, &isis_sr_global_block_label_range_cmd);
+ install_element(ISIS_NODE, &no_isis_sr_global_block_label_range_cmd);
+ install_element(ISIS_NODE, &isis_sr_node_msd_cmd);
+ install_element(ISIS_NODE, &no_isis_sr_node_msd_cmd);
+ install_element(ISIS_NODE, &isis_sr_prefix_sid_cmd);
+ install_element(ISIS_NODE, &no_isis_sr_prefix_sid_cmd);
+
install_element(INTERFACE_NODE, &isis_passive_cmd);
install_element(INTERFACE_NODE, &isis_passwd_cmd);
diff --git a/isisd/isis_errors.c b/isisd/isis_errors.c
index 755e70dbf6..7530d0b966 100644
--- a/isisd/isis_errors.c
+++ b/isisd/isis_errors.c
@@ -38,6 +38,12 @@ static struct log_ref ferr_isis_err[] = {
.suggestion = "Ensure configuration is correct"
},
{
+ .code = EC_ISIS_SID_OVERFLOW,
+ .title = "SID index overflow",
+ .description = "Isis has detected that a SID index falls outside of its associated SRGB range",
+ .suggestion = "Configure a larger SRGB"
+ },
+ {
.code = END_FERR,
}
};
diff --git a/isisd/isis_errors.h b/isisd/isis_errors.h
index 0732737607..d5674dbf30 100644
--- a/isisd/isis_errors.h
+++ b/isisd/isis_errors.h
@@ -26,6 +26,7 @@
enum isis_log_refs {
EC_ISIS_PACKET = ISIS_FERR_START,
EC_ISIS_CONFIG,
+ EC_ISIS_SID_OVERFLOW,
};
extern void isis_error_init(void);
diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c
index effd19ed7d..e578f616f4 100644
--- a/isisd/isis_lsp.c
+++ b/isisd/isis_lsp.c
@@ -55,6 +55,7 @@
#include "isisd/isis_mt.h"
#include "isisd/isis_tlvs.h"
#include "isisd/isis_te.h"
+#include "isisd/isis_sr.h"
#include "isisd/fabricd.h"
#include "isisd/isis_tx_queue.h"
#include "isisd/isis_nb.h"
@@ -763,9 +764,15 @@ static void lsp_build_ext_reach_ipv4(struct isis_lsp *lsp,
if (area->oldmetric)
isis_tlvs_add_oldstyle_ip_reach(lsp->tlvs, ipv4,
metric);
- if (area->newmetric)
- isis_tlvs_add_extended_ip_reach(lsp->tlvs, ipv4,
- metric);
+ if (area->newmetric) {
+ struct sr_prefix_cfg *pcfg = NULL;
+
+ if (area->srdb.enabled)
+ pcfg = isis_sr_cfg_prefix_find(area, ipv4);
+
+ isis_tlvs_add_extended_ip_reach(lsp->tlvs, ipv4, metric,
+ true, pcfg);
+ }
}
}
@@ -792,9 +799,14 @@ static void lsp_build_ext_reach_ipv6(struct isis_lsp *lsp,
metric = MAX_WIDE_PATH_METRIC;
if (!src_p || !src_p->prefixlen) {
+ struct sr_prefix_cfg *pcfg = NULL;
+
+ if (area->srdb.enabled)
+ pcfg = isis_sr_cfg_prefix_find(area, p);
+
isis_tlvs_add_ipv6_reach(lsp->tlvs,
isis_area_ipv6_topology(area),
- p, metric);
+ p, metric, true, pcfg);
} else if (isis_area_ipv6_dstsrc_enabled(area)) {
isis_tlvs_add_ipv6_dstsrc_reach(lsp->tlvs,
ISIS_MT_IPV6_DSTSRC,
@@ -910,6 +922,33 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
area->area_tag);
}
+ /* Add Router Capability TLV. */
+ if (isis->router_id != 0) {
+ struct isis_router_cap cap = {};
+
+ cap.router_id.s_addr = isis->router_id;
+
+ /* Add SR Sub-TLVs if SR is enabled. */
+ if (area->srdb.enabled) {
+ struct isis_sr_db *srdb = &area->srdb;
+ uint32_t range_size;
+
+ range_size = srdb->config.srgb_upper_bound
+ - srdb->config.srgb_lower_bound + 1;
+ cap.srgb.flags = ISIS_SUBTLV_SRGB_FLAG_I
+ | ISIS_SUBTLV_SRGB_FLAG_V;
+ cap.srgb.range_size = range_size;
+ cap.srgb.lower_bound = srdb->config.srgb_lower_bound;
+ cap.algo[0] = SR_ALGORITHM_SPF;
+ cap.algo[1] = SR_ALGORITHM_UNSET;
+ cap.msd = srdb->config.msd;
+ }
+
+ isis_tlvs_set_router_capability(lsp->tlvs, &cap);
+ lsp_debug("ISIS (%s): Adding Router Capabilities information",
+ area->area_tag);
+ }
+
/* IPv4 address and TE router ID TLVs.
* In case of the first one we don't follow "C" vendor,
* but "J" vendor behavior - one IPv4 address is put
@@ -996,13 +1035,21 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
}
if (area->newmetric) {
+ struct sr_prefix_cfg *pcfg = NULL;
+
lsp_debug(
"ISIS (%s): Adding te-style IP reachability for %s",
area->area_tag,
prefix2str(ipv4, buf,
sizeof(buf)));
+
+ if (area->srdb.enabled)
+ pcfg = isis_sr_cfg_prefix_find(
+ area, ipv4);
+
isis_tlvs_add_extended_ip_reach(
- lsp->tlvs, ipv4, metric);
+ lsp->tlvs, ipv4, metric, false,
+ pcfg);
}
}
}
@@ -1014,14 +1061,21 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area)
for (ALL_LIST_ELEMENTS_RO(circuit->ipv6_non_link,
ipnode, ipv6)) {
+ struct sr_prefix_cfg *pcfg = NULL;
+
lsp_debug(
"ISIS (%s): Adding IPv6 reachability for %s",
area->area_tag,
prefix2str(ipv6, buf, sizeof(buf)));
+
+ if (area->srdb.enabled)
+ pcfg = isis_sr_cfg_prefix_find(area,
+ ipv6);
+
isis_tlvs_add_ipv6_reach(
lsp->tlvs,
isis_area_ipv6_topology(area), ipv6,
- metric);
+ metric, false, pcfg);
}
}
diff --git a/isisd/isis_main.c b/isisd/isis_main.c
index 4c841dffe2..78654b2f1c 100644
--- a/isisd/isis_main.c
+++ b/isisd/isis_main.c
@@ -83,7 +83,9 @@ struct zebra_privs_t isisd_privs = {
.cap_num_i = 0};
/* isisd options */
-struct option longopts[] = {{0}};
+static const struct option longopts[] = {
+ {"int_num", required_argument, NULL, 'I'},
+ {0}};
/* Master of threads. */
struct thread_master *master;
@@ -99,6 +101,7 @@ void sigusr1(void);
static __attribute__((__noreturn__)) void terminate(int i)
{
+ isis_sr_term();
isis_zebra_stop();
exit(i);
}
@@ -196,13 +199,16 @@ FRR_DAEMON_INFO(isisd, ISIS, .vty_port = ISISD_VTY_PORT,
int main(int argc, char **argv, char **envp)
{
int opt;
+ int instance = 1;
#ifdef FABRICD
frr_preinit(&fabricd_di, argc, argv);
#else
frr_preinit(&isisd_di, argc, argv);
#endif
- frr_opt_add("", longopts, "");
+ frr_opt_add(
+ "I:", longopts,
+ " -I, --int_num Set instance number (label-manager)\n");
/* Command line argument treatment. */
while (1) {
@@ -214,6 +220,12 @@ int main(int argc, char **argv, char **envp)
switch (opt) {
case 0:
break;
+ case 'I':
+ instance = atoi(optarg);
+ if (instance < 1 || instance > (unsigned short)-1)
+ zlog_err("Instance %i out of range (1..%u)",
+ instance, (unsigned short)-1);
+ break;
default:
frr_help_exit(1);
break;
@@ -242,13 +254,14 @@ int main(int argc, char **argv, char **envp)
isis_redist_init();
isis_route_map_init();
isis_mpls_te_init();
+ isis_sr_init();
lsp_init();
mt_init();
/* create the global 'isis' instance */
isis_new(1, VRF_DEFAULT);
- isis_zebra_init(master);
+ isis_zebra_init(master, instance);
isis_bfd_init();
fabricd_init();
diff --git a/isisd/isis_misc.c b/isisd/isis_misc.c
index 25f7f8609b..27d06e8da7 100644
--- a/isisd/isis_misc.c
+++ b/isisd/isis_misc.c
@@ -538,6 +538,26 @@ void log_multiline(int priority, const char *prefix, const char *format, ...)
XFREE(MTYPE_TMP, p);
}
+char *log_uptime(time_t uptime, char *buf, size_t nbuf)
+{
+ struct tm *tm;
+ time_t difftime = time(NULL);
+ difftime -= uptime;
+ tm = gmtime(&difftime);
+
+ if (difftime < ONE_DAY_SECOND)
+ snprintf(buf, nbuf, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min,
+ tm->tm_sec);
+ else if (difftime < ONE_WEEK_SECOND)
+ snprintf(buf, nbuf, "%dd%02dh%02dm", tm->tm_yday, tm->tm_hour,
+ tm->tm_min);
+ else
+ snprintf(buf, nbuf, "%02dw%dd%02dh", tm->tm_yday / 7,
+ tm->tm_yday - ((tm->tm_yday / 7) * 7), tm->tm_hour);
+
+ return buf;
+}
+
void vty_multiline(struct vty *vty, const char *prefix, const char *format, ...)
{
char shortbuf[256];
diff --git a/isisd/isis_misc.h b/isisd/isis_misc.h
index fbfabaf24f..5cdbbfb058 100644
--- a/isisd/isis_misc.h
+++ b/isisd/isis_misc.h
@@ -80,6 +80,7 @@ enum { ISIS_UI_LEVEL_BRIEF,
#include "lib/log.h"
void log_multiline(int priority, const char *prefix, const char *format, ...)
PRINTFRR(3, 4);
+char *log_uptime(time_t uptime, char *buf, size_t nbuf);
struct vty;
void vty_multiline(struct vty *vty, const char *prefix, const char *format, ...)
PRINTFRR(3, 4);
diff --git a/isisd/isis_nb.c b/isisd/isis_nb.c
index da4322bd44..f1f183cc59 100644
--- a/isisd/isis_nb.c
+++ b/isisd/isis_nb.c
@@ -455,6 +455,68 @@ const struct frr_yang_module_info frr_isisd_info = {
},
},
{
+ .xpath = "/frr-isisd:isis/instance/segment-routing/enabled",
+ .cbs = {
+ .modify = isis_instance_segment_routing_enabled_modify,
+ .cli_show = cli_show_isis_sr_enabled,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/segment-routing/srgb",
+ .cbs = {
+ .apply_finish = isis_instance_segment_routing_srgb_apply_finish,
+ .cli_show = cli_show_isis_srgb,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/segment-routing/srgb/lower-bound",
+ .cbs = {
+ .modify = isis_instance_segment_routing_srgb_lower_bound_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/segment-routing/srgb/upper-bound",
+ .cbs = {
+ .modify = isis_instance_segment_routing_srgb_upper_bound_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/segment-routing/msd/node-msd",
+ .cbs = {
+ .modify = isis_instance_segment_routing_msd_node_msd_modify,
+ .destroy = isis_instance_segment_routing_msd_node_msd_destroy,
+ .cli_show = cli_show_isis_node_msd,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/segment-routing/prefix-sid-map/prefix-sid",
+ .cbs = {
+ .create = isis_instance_segment_routing_prefix_sid_map_prefix_sid_create,
+ .destroy = isis_instance_segment_routing_prefix_sid_map_prefix_sid_destroy,
+ .pre_validate = isis_instance_segment_routing_prefix_sid_map_prefix_sid_pre_validate,
+ .apply_finish = isis_instance_segment_routing_prefix_sid_map_prefix_sid_apply_finish,
+ .cli_show = cli_show_isis_prefix_sid,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/segment-routing/prefix-sid-map/prefix-sid/sid-value-type",
+ .cbs = {
+ .modify = isis_instance_segment_routing_prefix_sid_map_prefix_sid_sid_value_type_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/segment-routing/prefix-sid-map/prefix-sid/sid-value",
+ .cbs = {
+ .modify = isis_instance_segment_routing_prefix_sid_map_prefix_sid_sid_value_modify,
+ },
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/segment-routing/prefix-sid-map/prefix-sid/last-hop-behavior",
+ .cbs = {
+ .modify = isis_instance_segment_routing_prefix_sid_map_prefix_sid_last_hop_behavior_modify,
+ },
+ },
+ {
.xpath = "/frr-interface:lib/interface/frr-isisd:isis",
.cbs = {
.create = lib_interface_isis_create,
@@ -701,99 +763,105 @@ const struct frr_yang_module_info frr_isisd_info = {
},
},
{
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency",
+ .xpath = "/frr-interface:lib/interface/state/frr-isisd:isis",
+ .cbs = {
+ .get_elem = lib_interface_state_isis_get_elem,
+ }
+ },
+ {
+ .xpath = "/frr-interface:lib/interface/state/frr-isisd:isis/adjacencies/adjacency",
.cbs = {
- .get_next = lib_interface_isis_adjacencies_adjacency_get_next,
+ .get_next = lib_interface_state_isis_adjacencies_adjacency_get_next,
}
},
{
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-sys-type",
+ .xpath = "/frr-interface:lib/interface/state/frr-isisd:isis/adjacencies/adjacency/neighbor-sys-type",
.cbs = {
- .get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_sys_type_get_elem,
+ .get_elem = lib_interface_state_isis_adjacencies_adjacency_neighbor_sys_type_get_elem,
}
},
{
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-sysid",
+ .xpath = "/frr-interface:lib/interface/state/frr-isisd:isis/adjacencies/adjacency/neighbor-sysid",
.cbs = {
- .get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_sysid_get_elem,
+ .get_elem = lib_interface_state_isis_adjacencies_adjacency_neighbor_sysid_get_elem,
}
},
{
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-extended-circuit-id",
+ .xpath = "/frr-interface:lib/interface/state/frr-isisd:isis/adjacencies/adjacency/neighbor-extended-circuit-id",
.cbs = {
- .get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_extended_circuit_id_get_elem,
+ .get_elem = lib_interface_state_isis_adjacencies_adjacency_neighbor_extended_circuit_id_get_elem,
}
},
{
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-snpa",
+ .xpath = "/frr-interface:lib/interface/state/frr-isisd:isis/adjacencies/adjacency/neighbor-snpa",
.cbs = {
- .get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_snpa_get_elem,
+ .get_elem = lib_interface_state_isis_adjacencies_adjacency_neighbor_snpa_get_elem,
}
},
{
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/hold-timer",
+ .xpath = "/frr-interface:lib/interface/state/frr-isisd:isis/adjacencies/adjacency/hold-timer",
.cbs = {
- .get_elem = lib_interface_isis_adjacencies_adjacency_hold_timer_get_elem,
+ .get_elem = lib_interface_state_isis_adjacencies_adjacency_hold_timer_get_elem,
}
},
{
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-priority",
+ .xpath = "/frr-interface:lib/interface/state/frr-isisd:isis/adjacencies/adjacency/neighbor-priority",
.cbs = {
- .get_elem = lib_interface_isis_adjacencies_adjacency_neighbor_priority_get_elem,
+ .get_elem = lib_interface_state_isis_adjacencies_adjacency_neighbor_priority_get_elem,
}
},
{
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/state",
+ .xpath = "/frr-interface:lib/interface/state/frr-isisd:isis/adjacencies/adjacency/state",
.cbs = {
- .get_elem = lib_interface_isis_adjacencies_adjacency_state_get_elem,
+ .get_elem = lib_interface_state_isis_adjacencies_adjacency_state_get_elem,
}
},
{
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-changes",
+ .xpath = "/frr-interface:lib/interface/state/frr-isisd:isis/event-counters/adjacency-changes",
.cbs = {
- .get_elem = lib_interface_isis_event_counters_adjacency_changes_get_elem,
+ .get_elem = lib_interface_state_isis_event_counters_adjacency_changes_get_elem,
}
},
{
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-number",
+ .xpath = "/frr-interface:lib/interface/state/frr-isisd:isis/event-counters/adjacency-number",
.cbs = {
- .get_elem = lib_interface_isis_event_counters_adjacency_number_get_elem,
+ .get_elem = lib_interface_state_isis_event_counters_adjacency_number_get_elem,
}
},
{
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/init-fails",
+ .xpath = "/frr-interface:lib/interface/state/frr-isisd:isis/event-counters/init-fails",
.cbs = {
- .get_elem = lib_interface_isis_event_counters_init_fails_get_elem,
+ .get_elem = lib_interface_state_isis_event_counters_init_fails_get_elem,
}
},
{
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-rejects",
+ .xpath = "/frr-interface:lib/interface/state/frr-isisd:isis/event-counters/adjacency-rejects",
.cbs = {
- .get_elem = lib_interface_isis_event_counters_adjacency_rejects_get_elem,
+ .get_elem = lib_interface_state_isis_event_counters_adjacency_rejects_get_elem,
}
},
{
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/id-len-mismatch",
+ .xpath = "/frr-interface:lib/interface/state/frr-isisd:isis/event-counters/id-len-mismatch",
.cbs = {
- .get_elem = lib_interface_isis_event_counters_id_len_mismatch_get_elem,
+ .get_elem = lib_interface_state_isis_event_counters_id_len_mismatch_get_elem,
}
},
{
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/max-area-addresses-mismatch",
+ .xpath = "/frr-interface:lib/interface/state/frr-isisd:isis/event-counters/max-area-addresses-mismatch",
.cbs = {
- .get_elem = lib_interface_isis_event_counters_max_area_addresses_mismatch_get_elem,
+ .get_elem = lib_interface_state_isis_event_counters_max_area_addresses_mismatch_get_elem,
}
},
{
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/authentication-type-fails",
+ .xpath = "/frr-interface:lib/interface/state/frr-isisd:isis/event-counters/authentication-type-fails",
.cbs = {
- .get_elem = lib_interface_isis_event_counters_authentication_type_fails_get_elem,
+ .get_elem = lib_interface_state_isis_event_counters_authentication_type_fails_get_elem,
}
},
{
- .xpath = "/frr-interface:lib/interface/frr-isisd:isis/event-counters/authentication-fails",
+ .xpath = "/frr-interface:lib/interface/state/frr-isisd:isis/event-counters/authentication-fails",
.cbs = {
- .get_elem = lib_interface_isis_event_counters_authentication_fails_get_elem,
+ .get_elem = lib_interface_state_isis_event_counters_authentication_fails_get_elem,
}
},
{
diff --git a/isisd/isis_nb.h b/isisd/isis_nb.h
index 65aa95cd69..36dbc2d619 100644
--- a/isisd/isis_nb.h
+++ b/isisd/isis_nb.h
@@ -172,6 +172,28 @@ 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);
int lib_interface_isis_bfd_monitoring_modify(struct nb_cb_modify_args *args);
+int isis_instance_segment_routing_enabled_modify(
+ struct nb_cb_modify_args *args);
+int isis_instance_segment_routing_enabled_modify(
+ struct nb_cb_modify_args *args);
+int isis_instance_segment_routing_srgb_lower_bound_modify(
+ struct nb_cb_modify_args *args);
+int isis_instance_segment_routing_srgb_upper_bound_modify(
+ struct nb_cb_modify_args *args);
+int isis_instance_segment_routing_msd_node_msd_modify(
+ struct nb_cb_modify_args *args);
+int isis_instance_segment_routing_msd_node_msd_destroy(
+ struct nb_cb_destroy_args *args);
+int isis_instance_segment_routing_prefix_sid_map_prefix_sid_create(
+ struct nb_cb_create_args *args);
+int isis_instance_segment_routing_prefix_sid_map_prefix_sid_destroy(
+ struct nb_cb_destroy_args *args);
+int isis_instance_segment_routing_prefix_sid_map_prefix_sid_sid_value_type_modify(
+ struct nb_cb_modify_args *args);
+int isis_instance_segment_routing_prefix_sid_map_prefix_sid_sid_value_modify(
+ struct nb_cb_modify_args *args);
+int isis_instance_segment_routing_prefix_sid_map_prefix_sid_last_hop_behavior_modify(
+ struct nb_cb_modify_args *args);
int lib_interface_isis_csnp_interval_level_1_modify(
struct nb_cb_modify_args *args);
int lib_interface_isis_csnp_interval_level_2_modify(
@@ -216,47 +238,58 @@ int lib_interface_isis_multi_topology_ipv6_management_modify(
struct nb_cb_modify_args *args);
int lib_interface_isis_multi_topology_ipv6_dstsrc_modify(
struct nb_cb_modify_args *args);
-const void *lib_interface_isis_adjacencies_adjacency_get_next(
+struct yang_data *
+lib_interface_state_isis_get_elem(struct nb_cb_get_elem_args *args);
+const void *lib_interface_state_isis_adjacencies_adjacency_get_next(
struct nb_cb_get_next_args *args);
struct yang_data *
-lib_interface_isis_adjacencies_adjacency_neighbor_sys_type_get_elem(
+lib_interface_state_isis_adjacencies_adjacency_neighbor_sys_type_get_elem(
struct nb_cb_get_elem_args *args);
struct yang_data *
-lib_interface_isis_adjacencies_adjacency_neighbor_sysid_get_elem(
+lib_interface_state_isis_adjacencies_adjacency_neighbor_sysid_get_elem(
struct nb_cb_get_elem_args *args);
struct yang_data *
-lib_interface_isis_adjacencies_adjacency_neighbor_extended_circuit_id_get_elem(
+lib_interface_state_isis_adjacencies_adjacency_neighbor_extended_circuit_id_get_elem(
struct nb_cb_get_elem_args *args);
struct yang_data *
-lib_interface_isis_adjacencies_adjacency_neighbor_snpa_get_elem(
+lib_interface_state_isis_adjacencies_adjacency_neighbor_snpa_get_elem(
struct nb_cb_get_elem_args *args);
-struct yang_data *lib_interface_isis_adjacencies_adjacency_hold_timer_get_elem(
+struct yang_data *
+lib_interface_state_isis_adjacencies_adjacency_hold_timer_get_elem(
struct nb_cb_get_elem_args *args);
struct yang_data *
-lib_interface_isis_adjacencies_adjacency_neighbor_priority_get_elem(
+lib_interface_state_isis_adjacencies_adjacency_neighbor_priority_get_elem(
struct nb_cb_get_elem_args *args);
-struct yang_data *lib_interface_isis_adjacencies_adjacency_state_get_elem(
+struct yang_data *lib_interface_state_isis_adjacencies_adjacency_state_get_elem(
struct nb_cb_get_elem_args *args);
-struct yang_data *lib_interface_isis_event_counters_adjacency_changes_get_elem(
+struct yang_data *
+lib_interface_state_isis_event_counters_adjacency_changes_get_elem(
struct nb_cb_get_elem_args *args);
-struct yang_data *lib_interface_isis_event_counters_adjacency_number_get_elem(
+struct yang_data *
+lib_interface_state_isis_event_counters_adjacency_number_get_elem(
struct nb_cb_get_elem_args *args);
-struct yang_data *lib_interface_isis_event_counters_init_fails_get_elem(
+struct yang_data *lib_interface_state_isis_event_counters_init_fails_get_elem(
struct nb_cb_get_elem_args *args);
-struct yang_data *lib_interface_isis_event_counters_adjacency_rejects_get_elem(
+struct yang_data *
+lib_interface_state_isis_event_counters_adjacency_rejects_get_elem(
struct nb_cb_get_elem_args *args);
-struct yang_data *lib_interface_isis_event_counters_id_len_mismatch_get_elem(
+struct yang_data *
+lib_interface_state_isis_event_counters_id_len_mismatch_get_elem(
struct nb_cb_get_elem_args *args);
struct yang_data *
-lib_interface_isis_event_counters_max_area_addresses_mismatch_get_elem(
+lib_interface_state_isis_event_counters_max_area_addresses_mismatch_get_elem(
struct nb_cb_get_elem_args *args);
struct yang_data *
-lib_interface_isis_event_counters_authentication_type_fails_get_elem(
+lib_interface_state_isis_event_counters_authentication_type_fails_get_elem(
struct nb_cb_get_elem_args *args);
struct yang_data *
-lib_interface_isis_event_counters_authentication_fails_get_elem(
+lib_interface_state_isis_event_counters_authentication_fails_get_elem(
struct nb_cb_get_elem_args *args);
+/* Optional 'pre_validate' callbacks. */
+int isis_instance_segment_routing_prefix_sid_map_prefix_sid_pre_validate(
+ struct nb_cb_pre_validate_args *args);
+
/* Optional 'apply_finish' callbacks. */
void ietf_backoff_delay_apply_finish(struct nb_cb_apply_finish_args *args);
void area_password_apply_finish(struct nb_cb_apply_finish_args *args);
@@ -269,6 +302,10 @@ void default_info_origin_ipv6_apply_finish(
void redistribute_apply_finish(const struct lyd_node *dnode, int family);
void redistribute_ipv4_apply_finish(struct nb_cb_apply_finish_args *args);
void redistribute_ipv6_apply_finish(struct nb_cb_apply_finish_args *args);
+void isis_instance_segment_routing_srgb_apply_finish(
+ struct nb_cb_apply_finish_args *args);
+void isis_instance_segment_routing_prefix_sid_map_prefix_sid_apply_finish(
+ struct nb_cb_apply_finish_args *args);
/* Optional 'cli_show' callbacks. */
void cli_show_router_isis(struct vty *vty, struct lyd_node *dnode,
@@ -329,6 +366,14 @@ void cli_show_isis_mt_ipv6_mgmt(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
void cli_show_isis_mt_ipv6_dstsrc(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
+void cli_show_isis_sr_enabled(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_isis_srgb(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_isis_node_msd(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
+void cli_show_isis_prefix_sid(struct vty *vty, struct lyd_node *dnode,
+ bool show_defaults);
void cli_show_ip_isis_passive(struct vty *vty, struct lyd_node *dnode,
bool show_defaults);
void cli_show_ip_isis_password(struct vty *vty, struct lyd_node *dnode,
diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c
index 2f56fac186..a649e896fa 100644
--- a/isisd/isis_nb_config.c
+++ b/isisd/isis_nb_config.c
@@ -1403,6 +1403,289 @@ int isis_instance_mpls_te_router_address_destroy(
}
/*
+ * XPath: /frr-isisd:isis/instance/segment-routing/enabled
+ */
+int isis_instance_segment_routing_enabled_modify(
+ struct nb_cb_modify_args *args)
+{
+ struct isis_area *area;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ area = nb_running_get_entry(args->dnode, NULL, true);
+ area->srdb.config.enabled = yang_dnode_get_bool(args->dnode, NULL);
+
+ if (area->srdb.config.enabled) {
+ if (IS_DEBUG_ISIS(DEBUG_EVENTS))
+ zlog_debug("SR: Segment Routing: OFF -> ON");
+
+ if (isis_sr_start(area) == 0)
+ area->srdb.enabled = true;
+ } else {
+ if (IS_DEBUG_ISIS(DEBUG_EVENTS))
+ zlog_debug("SR: Segment Routing: ON -> OFF");
+
+ isis_sr_stop(area);
+ area->srdb.enabled = false;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/segment-routing/srgb
+ */
+void isis_instance_segment_routing_srgb_apply_finish(
+ struct nb_cb_apply_finish_args *args)
+{
+ struct isis_area *area;
+ uint32_t lower_bound, upper_bound;
+ int ret;
+
+ area = nb_running_get_entry(args->dnode, NULL, true);
+ lower_bound = yang_dnode_get_uint32(args->dnode, "./lower-bound");
+ upper_bound = yang_dnode_get_uint32(args->dnode, "./upper-bound");
+
+ ret = isis_sr_cfg_srgb_update(area, lower_bound, upper_bound);
+ if (area->srdb.config.enabled) {
+ if (ret == 0)
+ area->srdb.enabled = true;
+ else {
+ isis_sr_stop(area);
+ area->srdb.enabled = false;
+ }
+ }
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/segment-routing/srgb/lower-bound
+ */
+int isis_instance_segment_routing_srgb_lower_bound_modify(
+ struct nb_cb_modify_args *args)
+{
+ uint32_t lower_bound = yang_dnode_get_uint32(args->dnode, NULL);
+
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ if (!IS_MPLS_UNRESERVED_LABEL(lower_bound)) {
+ zlog_warn("Invalid SRGB lower bound: %" PRIu32,
+ lower_bound);
+ return NB_ERR_VALIDATION;
+ }
+ break;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/segment-routing/srgb/upper-bound
+ */
+int isis_instance_segment_routing_srgb_upper_bound_modify(
+ struct nb_cb_modify_args *args)
+{
+ uint32_t upper_bound = yang_dnode_get_uint32(args->dnode, NULL);
+
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ if (!IS_MPLS_UNRESERVED_LABEL(upper_bound)) {
+ zlog_warn("Invalid SRGB upper bound: %" PRIu32,
+ upper_bound);
+ return NB_ERR_VALIDATION;
+ }
+ break;
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ case NB_EV_APPLY:
+ break;
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/segment-routing/msd/node-msd
+ */
+int isis_instance_segment_routing_msd_node_msd_modify(
+ struct nb_cb_modify_args *args)
+{
+ struct isis_area *area;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ area = nb_running_get_entry(args->dnode, NULL, true);
+ area->srdb.config.msd = yang_dnode_get_uint8(args->dnode, NULL);
+
+ /* Update and regenerate LSP */
+ lsp_regenerate_schedule(area, area->is_type, 0);
+
+ return NB_OK;
+}
+
+int isis_instance_segment_routing_msd_node_msd_destroy(
+ struct nb_cb_destroy_args *args)
+{
+ struct isis_area *area;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ area = nb_running_get_entry(args->dnode, NULL, true);
+ area->srdb.config.msd = 0;
+
+ /* Update and regenerate LSP */
+ lsp_regenerate_schedule(area, area->is_type, 0);
+
+ return NB_OK;
+}
+
+/*
+ * XPath: /frr-isisd:isis/instance/segment-routing/prefix-sid-map/prefix-sid
+ */
+int isis_instance_segment_routing_prefix_sid_map_prefix_sid_create(
+ struct nb_cb_create_args *args)
+{
+ struct isis_area *area;
+ struct prefix prefix;
+ struct sr_prefix_cfg *pcfg;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ area = nb_running_get_entry(args->dnode, NULL, true);
+ yang_dnode_get_prefix(&prefix, args->dnode, "./prefix");
+
+ pcfg = isis_sr_cfg_prefix_add(area, &prefix);
+ nb_running_set_entry(args->dnode, pcfg);
+
+ return NB_OK;
+}
+
+int isis_instance_segment_routing_prefix_sid_map_prefix_sid_destroy(
+ struct nb_cb_destroy_args *args)
+{
+ struct sr_prefix_cfg *pcfg;
+ struct isis_area *area;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ pcfg = nb_running_unset_entry(args->dnode);
+ area = pcfg->area;
+ isis_sr_cfg_prefix_del(pcfg);
+ lsp_regenerate_schedule(area, area->is_type, 0);
+
+ return NB_OK;
+}
+
+int isis_instance_segment_routing_prefix_sid_map_prefix_sid_pre_validate(
+ struct nb_cb_pre_validate_args *args)
+{
+ uint32_t srgb_lbound;
+ uint32_t srgb_ubound;
+ uint32_t srgb_range;
+ uint32_t sid;
+ enum sr_sid_value_type sid_type;
+
+ srgb_lbound = yang_dnode_get_uint32(args->dnode,
+ "../../srgb/lower-bound");
+ srgb_ubound = yang_dnode_get_uint32(args->dnode,
+ "../../srgb/upper-bound");
+ sid = yang_dnode_get_uint32(args->dnode, "./sid-value");
+ sid_type = yang_dnode_get_enum(args->dnode, "./sid-value-type");
+
+ srgb_range = srgb_ubound - srgb_lbound + 1;
+ switch (sid_type) {
+ case SR_SID_VALUE_TYPE_INDEX:
+ if (sid >= srgb_range) {
+ zlog_warn("SID index %u falls outside local SRGB range",
+ sid);
+ return NB_ERR_VALIDATION;
+ }
+ break;
+ case SR_SID_VALUE_TYPE_ABSOLUTE:
+ if (!IS_MPLS_UNRESERVED_LABEL(sid)) {
+ zlog_warn("Invalid absolute SID %u", sid);
+ return NB_ERR_VALIDATION;
+ }
+ break;
+ }
+
+ return NB_OK;
+}
+
+void isis_instance_segment_routing_prefix_sid_map_prefix_sid_apply_finish(
+ struct nb_cb_apply_finish_args *args)
+{
+ struct sr_prefix_cfg *pcfg;
+ struct isis_area *area;
+
+ pcfg = nb_running_get_entry(args->dnode, NULL, true);
+ area = pcfg->area;
+ lsp_regenerate_schedule(area, area->is_type, 0);
+}
+
+/*
+ * XPath:
+ * /frr-isisd:isis/instance/segment-routing/prefix-sid-map/prefix-sid/sid-value-type
+ */
+int isis_instance_segment_routing_prefix_sid_map_prefix_sid_sid_value_type_modify(
+ struct nb_cb_modify_args *args)
+{
+ struct sr_prefix_cfg *pcfg;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ pcfg = nb_running_get_entry(args->dnode, NULL, true);
+ pcfg->sid_type = yang_dnode_get_enum(args->dnode, NULL);
+
+ return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-isisd:isis/instance/segment-routing/prefix-sid-map/prefix-sid/sid-value
+ */
+int isis_instance_segment_routing_prefix_sid_map_prefix_sid_sid_value_modify(
+ struct nb_cb_modify_args *args)
+{
+ struct sr_prefix_cfg *pcfg;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ pcfg = nb_running_get_entry(args->dnode, NULL, true);
+ pcfg->sid = yang_dnode_get_uint32(args->dnode, NULL);
+
+ return NB_OK;
+}
+
+/*
+ * XPath:
+ * /frr-isisd:isis/instance/segment-routing/prefix-sid-map/prefix-sid/last-hop-behavior
+ */
+int isis_instance_segment_routing_prefix_sid_map_prefix_sid_last_hop_behavior_modify(
+ struct nb_cb_modify_args *args)
+{
+ struct sr_prefix_cfg *pcfg;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ pcfg = nb_running_get_entry(args->dnode, NULL, true);
+ pcfg->last_hop_behavior = yang_dnode_get_enum(args->dnode, NULL);
+
+ return NB_OK;
+}
+
+/*
* XPath: /frr-interface:lib/interface/frr-isisd:isis
*/
int lib_interface_isis_create(struct nb_cb_create_args *args)
diff --git a/isisd/isis_nb_state.c b/isisd/isis_nb_state.c
index 1e44e60ee0..4e325ed8da 100644
--- a/isisd/isis_nb_state.c
+++ b/isisd/isis_nb_state.c
@@ -29,14 +29,35 @@
#include "isisd/isis_misc.h"
/*
- * XPath: /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency
+ * XPath: /frr-interface:lib/interface/state/frr-isisd:isis
*/
-const void *lib_interface_isis_adjacencies_adjacency_get_next(
+struct yang_data *
+lib_interface_state_isis_get_elem(struct nb_cb_get_elem_args *args)
+{
+ struct interface *ifp;
+ struct isis_circuit *circuit;
+
+ ifp = (struct interface *)args->list_entry;
+ if (!ifp)
+ return NULL;
+
+ circuit = circuit_scan_by_ifp(ifp);
+ if (!circuit || !circuit->area)
+ return NULL;
+
+ return yang_data_new(args->xpath, NULL);
+}
+
+/*
+ * XPath:
+ * /frr-interface:lib/interface/state/frr-isisd:isis/adjacencies/adjacency
+ */
+const void *lib_interface_state_isis_adjacencies_adjacency_get_next(
struct nb_cb_get_next_args *args)
{
struct interface *ifp;
struct isis_circuit *circuit;
- struct isis_adjacency *adj, *adj_next = NULL;
+ struct isis_adjacency *adj = NULL, *adj_next = NULL;
struct list *list;
struct listnode *node, *node_next;
@@ -54,17 +75,20 @@ const void *lib_interface_isis_adjacencies_adjacency_get_next(
case CIRCUIT_T_BROADCAST:
for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS;
level++) {
- adj = listnode_head(
- circuit->u.bc.adjdb[level - 1]);
- if (adj)
- break;
+ struct list *adjdb;
+
+ adjdb = circuit->u.bc.adjdb[level - 1];
+ if (adjdb) {
+ adj = listnode_head(adjdb);
+ if (adj)
+ break;
+ }
}
break;
case CIRCUIT_T_P2P:
adj = circuit->u.p2p.neighbor;
break;
default:
- adj = NULL;
break;
}
@@ -101,10 +125,10 @@ const void *lib_interface_isis_adjacencies_adjacency_get_next(
/*
* XPath:
- * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-sys-type
+ * /frr-interface:lib/interface/state/frr-isisd:isis/adjacencies/adjacency/neighbor-sys-type
*/
struct yang_data *
-lib_interface_isis_adjacencies_adjacency_neighbor_sys_type_get_elem(
+lib_interface_state_isis_adjacencies_adjacency_neighbor_sys_type_get_elem(
struct nb_cb_get_elem_args *args)
{
const struct isis_adjacency *adj = args->list_entry;
@@ -114,10 +138,10 @@ lib_interface_isis_adjacencies_adjacency_neighbor_sys_type_get_elem(
/*
* XPath:
- * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-sysid
+ * /frr-interface:lib/interface/state/frr-isisd:isis/adjacencies/adjacency/neighbor-sysid
*/
struct yang_data *
-lib_interface_isis_adjacencies_adjacency_neighbor_sysid_get_elem(
+lib_interface_state_isis_adjacencies_adjacency_neighbor_sysid_get_elem(
struct nb_cb_get_elem_args *args)
{
const struct isis_adjacency *adj = args->list_entry;
@@ -127,10 +151,10 @@ lib_interface_isis_adjacencies_adjacency_neighbor_sysid_get_elem(
/*
* XPath:
- * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-extended-circuit-id
+ * /frr-interface:lib/interface/state/frr-isisd:isis/adjacencies/adjacency/neighbor-extended-circuit-id
*/
struct yang_data *
-lib_interface_isis_adjacencies_adjacency_neighbor_extended_circuit_id_get_elem(
+lib_interface_state_isis_adjacencies_adjacency_neighbor_extended_circuit_id_get_elem(
struct nb_cb_get_elem_args *args)
{
const struct isis_adjacency *adj = args->list_entry;
@@ -140,10 +164,10 @@ lib_interface_isis_adjacencies_adjacency_neighbor_extended_circuit_id_get_elem(
/*
* XPath:
- * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-snpa
+ * /frr-interface:lib/interface/state/frr-isisd:isis/adjacencies/adjacency/neighbor-snpa
*/
struct yang_data *
-lib_interface_isis_adjacencies_adjacency_neighbor_snpa_get_elem(
+lib_interface_state_isis_adjacencies_adjacency_neighbor_snpa_get_elem(
struct nb_cb_get_elem_args *args)
{
const struct isis_adjacency *adj = args->list_entry;
@@ -153,9 +177,10 @@ lib_interface_isis_adjacencies_adjacency_neighbor_snpa_get_elem(
/*
* XPath:
- * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/hold-timer
+ * /frr-interface:lib/interface/state/frr-isisd:isis/adjacencies/adjacency/hold-timer
*/
-struct yang_data *lib_interface_isis_adjacencies_adjacency_hold_timer_get_elem(
+struct yang_data *
+lib_interface_state_isis_adjacencies_adjacency_hold_timer_get_elem(
struct nb_cb_get_elem_args *args)
{
const struct isis_adjacency *adj = args->list_entry;
@@ -165,10 +190,10 @@ struct yang_data *lib_interface_isis_adjacencies_adjacency_hold_timer_get_elem(
/*
* XPath:
- * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/neighbor-priority
+ * /frr-interface:lib/interface/state/frr-isisd:isis/adjacencies/adjacency/neighbor-priority
*/
struct yang_data *
-lib_interface_isis_adjacencies_adjacency_neighbor_priority_get_elem(
+lib_interface_state_isis_adjacencies_adjacency_neighbor_priority_get_elem(
struct nb_cb_get_elem_args *args)
{
const struct isis_adjacency *adj = args->list_entry;
@@ -178,9 +203,9 @@ lib_interface_isis_adjacencies_adjacency_neighbor_priority_get_elem(
/*
* XPath:
- * /frr-interface:lib/interface/frr-isisd:isis/adjacencies/adjacency/state
+ * /frr-interface:lib/interface/state/frr-isisd:isis/adjacencies/adjacency/state
*/
-struct yang_data *lib_interface_isis_adjacencies_adjacency_state_get_elem(
+struct yang_data *lib_interface_state_isis_adjacencies_adjacency_state_get_elem(
struct nb_cb_get_elem_args *args)
{
const struct isis_adjacency *adj = args->list_entry;
@@ -191,9 +216,10 @@ struct yang_data *lib_interface_isis_adjacencies_adjacency_state_get_elem(
/*
* XPath:
- * /frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-changes
+ * /frr-interface:lib/interface/state/frr-isisd:isis/event-counters/adjacency-changes
*/
-struct yang_data *lib_interface_isis_event_counters_adjacency_changes_get_elem(
+struct yang_data *
+lib_interface_state_isis_event_counters_adjacency_changes_get_elem(
struct nb_cb_get_elem_args *args)
{
struct interface *ifp;
@@ -212,9 +238,10 @@ struct yang_data *lib_interface_isis_event_counters_adjacency_changes_get_elem(
/*
* XPath:
- * /frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-number
+ * /frr-interface:lib/interface/state/frr-isisd:isis/event-counters/adjacency-number
*/
-struct yang_data *lib_interface_isis_event_counters_adjacency_number_get_elem(
+struct yang_data *
+lib_interface_state_isis_event_counters_adjacency_number_get_elem(
struct nb_cb_get_elem_args *args)
{
struct interface *ifp;
@@ -256,9 +283,10 @@ struct yang_data *lib_interface_isis_event_counters_adjacency_number_get_elem(
}
/*
- * XPath: /frr-interface:lib/interface/frr-isisd:isis/event-counters/init-fails
+ * XPath:
+ * /frr-interface:lib/interface/state/frr-isisd:isis/event-counters/init-fails
*/
-struct yang_data *lib_interface_isis_event_counters_init_fails_get_elem(
+struct yang_data *lib_interface_state_isis_event_counters_init_fails_get_elem(
struct nb_cb_get_elem_args *args)
{
struct interface *ifp;
@@ -277,9 +305,10 @@ struct yang_data *lib_interface_isis_event_counters_init_fails_get_elem(
/*
* XPath:
- * /frr-interface:lib/interface/frr-isisd:isis/event-counters/adjacency-rejects
+ * /frr-interface:lib/interface/state/frr-isisd:isis/event-counters/adjacency-rejects
*/
-struct yang_data *lib_interface_isis_event_counters_adjacency_rejects_get_elem(
+struct yang_data *
+lib_interface_state_isis_event_counters_adjacency_rejects_get_elem(
struct nb_cb_get_elem_args *args)
{
struct interface *ifp;
@@ -298,9 +327,10 @@ struct yang_data *lib_interface_isis_event_counters_adjacency_rejects_get_elem(
/*
* XPath:
- * /frr-interface:lib/interface/frr-isisd:isis/event-counters/id-len-mismatch
+ * /frr-interface:lib/interface/state/frr-isisd:isis/event-counters/id-len-mismatch
*/
-struct yang_data *lib_interface_isis_event_counters_id_len_mismatch_get_elem(
+struct yang_data *
+lib_interface_state_isis_event_counters_id_len_mismatch_get_elem(
struct nb_cb_get_elem_args *args)
{
struct interface *ifp;
@@ -319,10 +349,10 @@ struct yang_data *lib_interface_isis_event_counters_id_len_mismatch_get_elem(
/*
* XPath:
- * /frr-interface:lib/interface/frr-isisd:isis/event-counters/max-area-addresses-mismatch
+ * /frr-interface:lib/interface/state/frr-isisd:isis/event-counters/max-area-addresses-mismatch
*/
struct yang_data *
-lib_interface_isis_event_counters_max_area_addresses_mismatch_get_elem(
+lib_interface_state_isis_event_counters_max_area_addresses_mismatch_get_elem(
struct nb_cb_get_elem_args *args)
{
struct interface *ifp;
@@ -342,10 +372,10 @@ lib_interface_isis_event_counters_max_area_addresses_mismatch_get_elem(
/*
* XPath:
- * /frr-interface:lib/interface/frr-isisd:isis/event-counters/authentication-type-fails
+ * /frr-interface:lib/interface/state/frr-isisd:isis/event-counters/authentication-type-fails
*/
struct yang_data *
-lib_interface_isis_event_counters_authentication_type_fails_get_elem(
+lib_interface_state_isis_event_counters_authentication_type_fails_get_elem(
struct nb_cb_get_elem_args *args)
{
struct interface *ifp;
@@ -364,10 +394,10 @@ lib_interface_isis_event_counters_authentication_type_fails_get_elem(
/*
* XPath:
- * /frr-interface:lib/interface/frr-isisd:isis/event-counters/authentication-fails
+ * /frr-interface:lib/interface/state/frr-isisd:isis/event-counters/authentication-fails
*/
struct yang_data *
-lib_interface_isis_event_counters_authentication_fails_get_elem(
+lib_interface_state_isis_event_counters_authentication_fails_get_elem(
struct nb_cb_get_elem_args *args)
{
struct interface *ifp;
diff --git a/isisd/isis_route.c b/isisd/isis_route.c
index 05394e0fe4..fa6af6c216 100644
--- a/isisd/isis_route.c
+++ b/isisd/isis_route.c
@@ -65,32 +65,19 @@ static struct isis_nexthop *isis_nexthop_create(int family, union g_addr *ip,
{
struct isis_nexthop *nexthop;
- nexthop = nexthoplookup(isis->nexthops, family, ip, ifindex);
- if (nexthop) {
- nexthop->lock++;
- return nexthop;
- }
-
nexthop = XCALLOC(MTYPE_ISIS_NEXTHOP, sizeof(struct isis_nexthop));
nexthop->family = family;
nexthop->ifindex = ifindex;
nexthop->ip = *ip;
- listnode_add(isis->nexthops, nexthop);
- nexthop->lock++;
+ isis_sr_nexthop_reset(&nexthop->sr);
return nexthop;
}
static void isis_nexthop_delete(struct isis_nexthop *nexthop)
{
- nexthop->lock--;
- if (nexthop->lock == 0) {
- listnode_delete(isis->nexthops, nexthop);
- XFREE(MTYPE_ISIS_NEXTHOP, nexthop);
- }
-
- return;
+ XFREE(MTYPE_ISIS_NEXTHOP, nexthop);
}
static struct isis_nexthop *nexthoplookup(struct list *nexthops, int family,
@@ -143,6 +130,7 @@ static void adjinfo2nexthop(int family, struct list *nexthops,
nh = isis_nexthop_create(
AF_INET, &ip,
adj->circuit->interface->ifindex);
+ memcpy(nh->sysid, adj->sysid, sizeof(nh->sysid));
listnode_add(nexthops, nh);
break;
}
@@ -157,6 +145,7 @@ static void adjinfo2nexthop(int family, struct list *nexthops,
nh = isis_nexthop_create(
AF_INET6, &ip,
adj->circuit->interface->ifindex);
+ memcpy(nh->sysid, adj->sysid, sizeof(nh->sysid));
listnode_add(nexthops, nh);
break;
}
diff --git a/isisd/isis_route.h b/isisd/isis_route.h
index 2326bb8228..0356668d7e 100644
--- a/isisd/isis_route.h
+++ b/isisd/isis_route.h
@@ -31,7 +31,8 @@ struct isis_nexthop {
ifindex_t ifindex;
int family;
union g_addr ip;
- unsigned int lock;
+ uint8_t sysid[ISIS_SYS_ID_LEN];
+ struct sr_nexthop_info sr;
};
struct isis_route_info {
diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c
index 30b9f88615..3091650ef1 100644
--- a/isisd/isis_spf.c
+++ b/isisd/isis_spf.c
@@ -1214,6 +1214,8 @@ static int isis_run_spf_cb(struct thread *thread)
isis_area_verify_routes(area);
+ isis_area_verify_sr(area);
+
/* walk all circuits and reset any spf specific flags */
struct listnode *node;
struct isis_circuit *circuit;
diff --git a/isisd/isis_sr.c b/isisd/isis_sr.c
new file mode 100644
index 0000000000..c24c0608b2
--- /dev/null
+++ b/isisd/isis_sr.c
@@ -0,0 +1,1970 @@
+/*
+ * This is an implementation of Segment Routing for IS-IS as per RFC 8667
+ *
+ * Copyright (C) 2019 Orange http://www.orange.com
+ *
+ * Author: Olivier Dugeon <olivier.dugeon@orange.com>
+ * Contributor: Renato Westphal <renato@opensourcerouting.org> for NetDEF
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include <zebra.h>
+
+#include "if.h"
+#include "linklist.h"
+#include "log.h"
+#include "command.h"
+#include "termtable.h"
+#include "memory.h"
+#include "prefix.h"
+#include "table.h"
+#include "vty.h"
+#include "zclient.h"
+#include "lib/lib_errors.h"
+
+#include "isisd/isisd.h"
+#include "isisd/isis_spf.h"
+#include "isisd/isis_spf_private.h"
+#include "isisd/isis_adjacency.h"
+#include "isisd/isis_route.h"
+#include "isisd/isis_mt.h"
+#include "isisd/isis_sr.h"
+#include "isisd/isis_tlvs.h"
+#include "isisd/isis_misc.h"
+#include "isisd/isis_zebra.h"
+#include "isisd/isis_errors.h"
+
+/* Local variables and functions */
+DEFINE_MTYPE_STATIC(ISISD, ISIS_SR_INFO, "ISIS segment routing information")
+
+static void sr_prefix_uninstall(struct sr_prefix *srp);
+static void sr_prefix_reinstall(struct sr_prefix *srp, bool make_before_break);
+
+/* --- RB-Tree Management functions ----------------------------------------- */
+
+/**
+ * SR Prefix comparison for RB-Tree.
+ *
+ * @param a First SR prefix
+ * @param b Second SR prefix
+ *
+ * @return -1 (a < b), 0 (a == b) or +1 (a > b)
+ */
+static inline int sr_prefix_sid_compare(const struct sr_prefix *a,
+ const struct sr_prefix *b)
+{
+ return prefix_cmp(&a->prefix, &b->prefix);
+}
+DECLARE_RBTREE_UNIQ(srdb_node_prefix, struct sr_prefix, node_entry,
+ sr_prefix_sid_compare)
+DECLARE_RBTREE_UNIQ(srdb_area_prefix, struct sr_prefix, area_entry,
+ sr_prefix_sid_compare)
+
+/**
+ * Configured SR Prefix comparison for RB-Tree.
+ *
+ * @param a First SR prefix
+ * @param b Second SR prefix
+ *
+ * @return -1 (a < b), 0 (a == b) or +1 (a > b)
+ */
+static inline int sr_prefix_sid_cfg_compare(const struct sr_prefix_cfg *a,
+ const struct sr_prefix_cfg *b)
+{
+ return prefix_cmp(&a->prefix, &b->prefix);
+}
+DECLARE_RBTREE_UNIQ(srdb_prefix_cfg, struct sr_prefix_cfg, entry,
+ sr_prefix_sid_cfg_compare)
+
+/**
+ * SR Node comparison for RB-Tree.
+ *
+ * @param a First SR node
+ * @param b Second SR node
+ *
+ * @return -1 (a < b), 0 (a == b) or +1 (a > b)
+ */
+static inline int sr_node_compare(const struct sr_node *a,
+ const struct sr_node *b)
+{
+ return memcmp(a->sysid, b->sysid, ISIS_SYS_ID_LEN);
+}
+DECLARE_RBTREE_UNIQ(srdb_node, struct sr_node, entry, sr_node_compare)
+
+/* --- Functions used for Yang model and CLI to configure Segment Routing --- */
+
+/**
+ * Check if prefix correspond to a Node SID.
+ *
+ * @param ifp Interface
+ * @param prefix Prefix to be checked
+ *
+ * @return True if the interface/address pair corresponds to a Node-SID
+ */
+static bool sr_prefix_is_node_sid(const struct interface *ifp,
+ const struct prefix *prefix)
+{
+ return (if_is_loopback(ifp) && is_host_route(prefix));
+}
+
+/**
+ * Update local SRGB configuration. SRGB is reserved though Label Manager.
+ * This function trigger the update of local Prefix-SID installation.
+ *
+ * @param area IS-IS area
+ * @param lower_bound Lower bound of SRGB
+ * @param upper_bound Upper bound of SRGB
+ *
+ * @return 0 on success, -1 otherwise
+ */
+int isis_sr_cfg_srgb_update(struct isis_area *area, uint32_t lower_bound,
+ uint32_t upper_bound)
+{
+ struct isis_sr_db *srdb = &area->srdb;
+
+ sr_debug("ISIS-Sr (%s): Update SRGB", area->area_tag);
+
+ /* First release the old SRGB. */
+ if (srdb->config.enabled)
+ isis_zebra_release_label_range(srdb->config.srgb_lower_bound,
+ srdb->config.srgb_upper_bound);
+
+ srdb->config.srgb_lower_bound = lower_bound;
+ srdb->config.srgb_upper_bound = upper_bound;
+
+ if (srdb->enabled) {
+ struct sr_prefix *srp;
+
+ /* Request new SRGB if SR is enabled. */
+ if (isis_zebra_request_label_range(
+ srdb->config.srgb_lower_bound,
+ srdb->config.srgb_upper_bound
+ - srdb->config.srgb_lower_bound + 1))
+ return -1;
+
+ sr_debug(" |- Got new SRGB %u/%u",
+ srdb->config.srgb_lower_bound,
+ srdb->config.srgb_upper_bound);
+
+ /* Reinstall local Prefix-SIDs to update their input labels. */
+ for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
+ frr_each (srdb_area_prefix,
+ &area->srdb.prefix_sids[level - 1], srp) {
+ sr_prefix_reinstall(srp, false);
+ }
+ }
+
+ lsp_regenerate_schedule(area, area->is_type, 0);
+ } else if (srdb->config.enabled) {
+ /* Try to enable SR again using the new SRGB. */
+ if (isis_sr_start(area) == 0)
+ area->srdb.enabled = true;
+ }
+
+ return 0;
+}
+
+/**
+ * Add new Prefix-SID configuration to the SRDB.
+ *
+ * @param area IS-IS area
+ * @param prefix Prefix to be added
+ *
+ * @return Newly added Prefix-SID configuration structure
+ */
+struct sr_prefix_cfg *isis_sr_cfg_prefix_add(struct isis_area *area,
+ const struct prefix *prefix)
+{
+ struct sr_prefix_cfg *pcfg;
+ struct interface *ifp;
+
+ sr_debug("ISIS-Sr (%s): Add local prefix %pFX", area->area_tag, prefix);
+
+ pcfg = XCALLOC(MTYPE_ISIS_SR_INFO, sizeof(*pcfg));
+ pcfg->prefix = *prefix;
+ pcfg->area = area;
+
+ /* Pull defaults from the YANG module. */
+ pcfg->sid_type = yang_get_default_enum(
+ "%s/prefix-sid-map/prefix-sid/sid-value-type", ISIS_SR);
+ pcfg->last_hop_behavior = yang_get_default_enum(
+ "%s/prefix-sid-map/prefix-sid/last-hop-behavior", ISIS_SR);
+
+ /* Set the N-flag when appropriate. */
+ ifp = if_lookup_prefix(prefix, VRF_DEFAULT);
+ if (ifp && sr_prefix_is_node_sid(ifp, prefix))
+ pcfg->node_sid = true;
+
+ /* Save prefix-sid configuration. */
+ srdb_prefix_cfg_add(&area->srdb.config.prefix_sids, pcfg);
+
+ return pcfg;
+}
+
+/**
+ * Removal of locally configured Prefix-SID.
+ *
+ * @param pcfg Configured Prefix-SID
+ */
+void isis_sr_cfg_prefix_del(struct sr_prefix_cfg *pcfg)
+{
+ struct isis_area *area = pcfg->area;
+
+ sr_debug("ISIS-Sr (%s): Delete local Prefix-SID %pFX %s %u",
+ area->area_tag, &pcfg->prefix,
+ pcfg->sid_type == SR_SID_VALUE_TYPE_INDEX ? "index" : "label",
+ pcfg->sid);
+
+ srdb_prefix_cfg_del(&area->srdb.config.prefix_sids, pcfg);
+ XFREE(MTYPE_ISIS_SR_INFO, pcfg);
+}
+
+/**
+ * Lookup for Prefix-SID in the local configuration.
+ *
+ * @param area IS-IS area
+ * @param prefix Prefix to lookup
+ *
+ * @return Configured Prefix-SID structure if found, NULL otherwise
+ */
+struct sr_prefix_cfg *isis_sr_cfg_prefix_find(struct isis_area *area,
+ union prefixconstptr prefix)
+{
+ struct sr_prefix_cfg pcfg = {};
+
+ prefix_copy(&pcfg.prefix, prefix.p);
+ return srdb_prefix_cfg_find(&area->srdb.config.prefix_sids, &pcfg);
+}
+
+/**
+ * Fill in Prefix-SID Sub-TLV according to the corresponding configuration.
+ *
+ * @param pcfg Prefix-SID configuration
+ * @param external False if prefix is locally configured, true otherwise
+ * @param psid Prefix-SID sub-TLV to be updated
+ */
+void isis_sr_prefix_cfg2subtlv(const struct sr_prefix_cfg *pcfg, bool external,
+ struct isis_prefix_sid *psid)
+{
+ /* Set SID algorithm. */
+ psid->algorithm = SR_ALGORITHM_SPF;
+
+ /* Set SID flags. */
+ psid->flags = 0;
+ switch (pcfg->last_hop_behavior) {
+ case SR_LAST_HOP_BEHAVIOR_EXP_NULL:
+ SET_FLAG(psid->flags, ISIS_PREFIX_SID_NO_PHP);
+ SET_FLAG(psid->flags, ISIS_PREFIX_SID_EXPLICIT_NULL);
+ break;
+ case SR_LAST_HOP_BEHAVIOR_NO_PHP:
+ SET_FLAG(psid->flags, ISIS_PREFIX_SID_NO_PHP);
+ UNSET_FLAG(psid->flags, ISIS_PREFIX_SID_EXPLICIT_NULL);
+ break;
+ case SR_LAST_HOP_BEHAVIOR_PHP:
+ UNSET_FLAG(psid->flags, ISIS_PREFIX_SID_NO_PHP);
+ UNSET_FLAG(psid->flags, ISIS_PREFIX_SID_EXPLICIT_NULL);
+ break;
+ }
+ if (external)
+ SET_FLAG(psid->flags, ISIS_PREFIX_SID_READVERTISED);
+ if (pcfg->node_sid)
+ SET_FLAG(psid->flags, ISIS_PREFIX_SID_NODE);
+
+ /* Set SID value. */
+ psid->value = pcfg->sid;
+ if (pcfg->sid_type == SR_SID_VALUE_TYPE_ABSOLUTE) {
+ SET_FLAG(psid->flags, ISIS_PREFIX_SID_VALUE);
+ SET_FLAG(psid->flags, ISIS_PREFIX_SID_LOCAL);
+ }
+}
+
+/* --- Segment Routing Prefix Management functions -------------------------- */
+
+/**
+ * Add Segment Routing Prefix to a given Segment Routing Node.
+ *
+ * @param area IS-IS area
+ * @param srn Segment Routing Node
+ * @param prefix Prefix to be added
+ * @param local True if prefix is locally configured, false otherwise
+ * @param psid Prefix-SID sub-TLVs
+ *
+ * @return New Segment Routing Prefix structure
+ */
+static struct sr_prefix *sr_prefix_add(struct isis_area *area,
+ struct sr_node *srn,
+ union prefixconstptr prefix, bool local,
+ const struct isis_prefix_sid *psid)
+{
+ struct sr_prefix *srp;
+
+ srp = XCALLOC(MTYPE_ISIS_SR_INFO, sizeof(*srp));
+ prefix_copy(&srp->prefix, prefix.p);
+ srp->sid = *psid;
+ srp->input_label = MPLS_INVALID_LABEL;
+ if (local) {
+ srp->type = ISIS_SR_PREFIX_LOCAL;
+ isis_sr_nexthop_reset(&srp->u.local.info);
+ } else {
+ srp->type = ISIS_SR_PREFIX_REMOTE;
+ srp->u.remote.rinfo = NULL;
+ }
+ srp->srn = srn;
+ srdb_node_prefix_add(&srn->prefix_sids, srp);
+ /* TODO: this might fail if we have Anycast SIDs in the IS-IS area. */
+ srdb_area_prefix_add(&area->srdb.prefix_sids[srn->level - 1], srp);
+
+ sr_debug(" |- Added new SR Prefix-SID %pFX %s %u to SR Node %s",
+ &srp->prefix, IS_SID_VALUE(srp->sid.flags) ? "label" : "index",
+ srp->sid.value, sysid_print(srn->sysid));
+
+ return srp;
+}
+
+/**
+ * Remove given Segment Prefix from given Segment Routing Node.
+ * Prefix-SID is un-installed first.
+ *
+ * @param area IS-IS area
+ * @param srn Segment Routing Node
+ * @param srp Segment Routing Prefix
+ */
+static void sr_prefix_del(struct isis_area *area, struct sr_node *srn,
+ struct sr_prefix *srp)
+{
+ sr_debug(" |- Delete SR Prefix-SID %pFX %s %u to SR Node %s",
+ &srp->prefix, IS_SID_VALUE(srp->sid.flags) ? "label" : "index",
+ srp->sid.value, sysid_print(srn->sysid));
+
+ sr_prefix_uninstall(srp);
+ srdb_node_prefix_del(&srn->prefix_sids, srp);
+ srdb_area_prefix_del(&area->srdb.prefix_sids[srn->level - 1], srp);
+ XFREE(MTYPE_ISIS_SR_INFO, srp);
+}
+
+/**
+ * Find Segment Routing Prefix by Area.
+ *
+ * @param area IS-IS area
+ * @param level IS-IS level
+ * @param prefix Prefix to lookup
+ *
+ * @return Segment Routing Prefix structure if found, NULL otherwise
+ */
+static struct sr_prefix *sr_prefix_find_by_area(struct isis_area *area,
+ int level,
+ union prefixconstptr prefix)
+{
+ struct sr_prefix srp = {};
+
+ prefix_copy(&srp.prefix, prefix.p);
+ return srdb_area_prefix_find(&area->srdb.prefix_sids[level - 1], &srp);
+}
+
+/**
+ * Find Segment Routing Prefix by Segment Routing Node.
+ *
+ * @param srn Segment Routing Node
+ * @param prefix Prefix to lookup
+ *
+ * @return Segment Routing Prefix structure if found, NULL otherwise
+ */
+static struct sr_prefix *sr_prefix_find_by_node(struct sr_node *srn,
+ union prefixconstptr prefix)
+{
+ struct sr_prefix srp = {};
+
+ prefix_copy(&srp.prefix, prefix.p);
+ return srdb_node_prefix_find(&srn->prefix_sids, &srp);
+}
+
+/* --- Segment Routing Node Management functions ---------------------------- */
+
+/**
+ * Add Segment Routing Node to the Segment Routing Data Base.
+ *
+ * @param area IS-IS area
+ * @param level IS-IS level
+ * @param sysid Node System ID
+ * @param cap Segment Routing Capability sub-TLVs
+ *
+ * @return New Segment Routing Node structure
+ */
+static struct sr_node *sr_node_add(struct isis_area *area, int level,
+ const uint8_t *sysid,
+ const struct isis_router_cap *cap)
+{
+ struct sr_node *srn;
+
+ srn = XCALLOC(MTYPE_ISIS_SR_INFO, sizeof(*srn));
+ srn->level = level;
+ memcpy(srn->sysid, sysid, ISIS_SYS_ID_LEN);
+ srn->cap = *cap;
+ srn->area = area;
+ srdb_node_prefix_init(&srn->prefix_sids);
+ srdb_node_add(&area->srdb.sr_nodes[level - 1], srn);
+
+ sr_debug(" |- Added new SR Node %s", sysid_print(srn->sysid));
+
+ return srn;
+}
+
+static void sr_node_del(struct isis_area *area, int level, struct sr_node *srn)
+/**
+ * Remove Segment Routing Node from the Segment Routing Data Base.
+ * All Prefix-SID attached to this Segment Routing Node are removed first.
+ *
+ * @param area IS-IS area
+ * @param level IS-IS level
+ * @param srn Segment Routing Node to be deleted
+ */
+{
+
+ sr_debug(" |- Delete SR Node %s", sysid_print(srn->sysid));
+
+ /* Remove and uninstall Prefix-SIDs. */
+ while (srdb_node_prefix_count(&srn->prefix_sids) > 0) {
+ struct sr_prefix *srp;
+
+ srp = srdb_node_prefix_first(&srn->prefix_sids);
+ sr_prefix_del(area, srn, srp);
+ }
+
+ srdb_node_del(&area->srdb.sr_nodes[level - 1], srn);
+ XFREE(MTYPE_ISIS_SR_INFO, srn);
+}
+
+/**
+ * Find Segment Routing Node in the Segment Routing Data Base per system ID.
+ *
+ * @param area IS-IS area
+ * @param level IS-IS level
+ * @param sysid Node System ID to lookup
+ *
+ * @return Segment Routing Node structure if found, NULL otherwise
+ */
+static struct sr_node *sr_node_find(struct isis_area *area, int level,
+ const uint8_t *sysid)
+{
+ struct sr_node srn = {};
+
+ memcpy(srn.sysid, sysid, ISIS_SYS_ID_LEN);
+ return srdb_node_find(&area->srdb.sr_nodes[level - 1], &srn);
+}
+
+/**
+ * Update Segment Routing Node following an SRGB update. This function
+ * is called when a neighbor SR Node has updated its SRGB.
+ *
+ * @param area IS-IS area
+ * @param level IS-IS level
+ * @param sysid Segment Routing Node system ID
+ */
+static void sr_node_srgb_update(struct isis_area *area, int level,
+ uint8_t *sysid)
+{
+ struct sr_prefix *srp;
+
+ sr_debug("ISIS-Sr (%s): Update neighbors SR Node with new SRGB",
+ area->area_tag);
+
+ frr_each (srdb_area_prefix, &area->srdb.prefix_sids[level - 1], srp) {
+ struct listnode *node;
+ struct isis_nexthop *nh;
+
+ if (srp->type == ISIS_SR_PREFIX_LOCAL)
+ continue;
+
+ if (srp->u.remote.rinfo == NULL)
+ continue;
+
+ for (ALL_LIST_ELEMENTS_RO(srp->u.remote.rinfo->nexthops, node,
+ nh)) {
+ if (memcmp(nh->sysid, sysid, ISIS_SYS_ID_LEN) != 0)
+ continue;
+
+ /*
+ * The Prefix-SID input label hasn't changed. We could
+ * re-install all Prefix-SID with "Make Before Break"
+ * option. Zebra layer will update output label(s) by
+ * adding new entry before removing the old one(s).
+ */
+ sr_prefix_reinstall(srp, true);
+ break;
+ }
+ }
+}
+
+/* --- Segment Routing Nexthop information Management functions ------------- */
+
+/**
+ * Update Segment Routing Nexthop.
+ *
+ * @param srnh Segment Routing next hop
+ * @param label Output MPLS label
+ */
+void isis_sr_nexthop_update(struct sr_nexthop_info *srnh, mpls_label_t label)
+{
+ srnh->label = label;
+ if (srnh->uptime == 0)
+ srnh->uptime = time(NULL);
+}
+
+/**
+ * Reset Segment Routing Nexthop.
+ *
+ * @param srnh Segment Routing Nexthop
+ */
+void isis_sr_nexthop_reset(struct sr_nexthop_info *srnh)
+{
+ srnh->label = MPLS_INVALID_LABEL;
+ srnh->uptime = 0;
+}
+
+/* --- Segment Routing Prefix-SID Management functions to configure LFIB ---- */
+
+/**
+ * Lookup IS-IS route in the Shortest Path Tree.
+ *
+ * @param area IS-IS area
+ * @param tree_id Shortest Path Tree identifier
+ * @param srp Segment Routing Prefix to lookup
+ *
+ * @return Route Information for this prefix if found, NULL otherwise
+ */
+static struct isis_route_info *sr_prefix_lookup_route(struct isis_area *area,
+ enum spf_tree_id tree_id,
+ struct sr_prefix *srp)
+{
+ struct route_node *rn;
+ int level = srp->srn->level;
+
+ rn = route_node_lookup(area->spftree[tree_id][level - 1]->route_table,
+ &srp->prefix);
+ if (rn) {
+ route_unlock_node(rn);
+ if (rn->info)
+ return rn->info;
+ }
+
+ return NULL;
+}
+
+/**
+ * Compute input label for the given Prefix-SID.
+ *
+ * @param srp Segment Routing Prefix
+ *
+ * @return MPLS label or MPLS_INVALID_LABEL in case of SRGB overflow
+ */
+static mpls_label_t sr_prefix_in_label(const struct sr_prefix *srp)
+{
+ const struct sr_node *srn = srp->srn;
+ struct isis_area *area = srn->area;
+
+ /* Return SID value as MPLS label if it is an Absolute SID */
+ if (CHECK_FLAG(srp->sid.flags,
+ ISIS_PREFIX_SID_VALUE | ISIS_PREFIX_SID_LOCAL))
+ return srp->sid.value;
+
+ /* Check that SID index falls inside the SRGB */
+ if (srp->sid.value >= (area->srdb.config.srgb_upper_bound
+ - area->srdb.config.srgb_lower_bound + 1)) {
+ flog_warn(EC_ISIS_SID_OVERFLOW,
+ "%s: SID index %u falls outside local SRGB range",
+ __func__, srp->sid.value);
+ return MPLS_INVALID_LABEL;
+ }
+
+ /* Return MPLS label as SID index + SRGB_lower_bound as per RFC 8667 */
+ return (area->srdb.config.srgb_lower_bound + srp->sid.value);
+}
+
+/**
+ * Compute output label for the given Prefix-SID.
+ *
+ * @param srp Segment Routing Prefix
+ * @param srn_nexthop Segment Routing nexthop node
+ * @param sysid System ID of the SR node which advertised the Prefix-SID
+ *
+ * @return MPLS label or MPLS_INVALID_LABEL in case of error
+ */
+static mpls_label_t sr_prefix_out_label(const struct sr_prefix *srp,
+ const struct sr_node *srn_nexthop,
+ const uint8_t *sysid)
+{
+ const struct sr_node *srn = srp->srn;
+
+ /* Check if the nexthop SR Node is the last hop? */
+ if (memcmp(sysid, srn->sysid, ISIS_SYS_ID_LEN) == 0) {
+ /* SR-Node doesn't request NO-PHP. Return Implicit NULL label */
+ if (!CHECK_FLAG(srp->sid.flags, ISIS_PREFIX_SID_NO_PHP))
+ return MPLS_LABEL_IMPLICIT_NULL;
+
+ /* SR-Node requests Implicit NULL Label */
+ if (CHECK_FLAG(srp->sid.flags, ISIS_PREFIX_SID_EXPLICIT_NULL)) {
+ if (srp->prefix.family == AF_INET)
+ return MPLS_LABEL_IPV4_EXPLICIT_NULL;
+ else
+ return MPLS_LABEL_IPV6_EXPLICIT_NULL;
+ }
+ /* Fallthrough */
+ }
+
+ /* Return SID value as MPLS label if it is an Absolute SID */
+ if (CHECK_FLAG(srp->sid.flags,
+ ISIS_PREFIX_SID_VALUE | ISIS_PREFIX_SID_LOCAL)) {
+ /*
+ * V/L SIDs have local significance, so only adjacent routers
+ * can use them (RFC8667 section #2.1.1.1)
+ */
+ if (srp->srn != srn_nexthop)
+ return MPLS_INVALID_LABEL;
+ return srp->sid.value;
+ }
+
+ /* Check that SID index falls inside the SRGB */
+ if (srp->sid.value >= srn_nexthop->cap.srgb.range_size) {
+ flog_warn(EC_ISIS_SID_OVERFLOW,
+ "%s: SID index %u falls outside remote SRGB range",
+ __func__, srp->sid.value);
+ return MPLS_INVALID_LABEL;
+ }
+
+ /* Return MPLS label as SID index + SRGB_lower_bound as per RFC 8667 */
+ return (srn_nexthop->cap.srgb.lower_bound + srp->sid.value);
+}
+
+/**
+ * Process local Prefix-SID and install it if possible. Input label is
+ * computed before installing it in LFIB.
+ *
+ * @param srp Segment Routing Prefix
+ *
+ * @return 0 on success, -1 otherwise
+ */
+static int sr_prefix_install_local(struct sr_prefix *srp)
+{
+ mpls_label_t input_label;
+ const struct sr_node *srn = srp->srn;
+
+ /*
+ * No need to install Label for local Prefix-SID unless the
+ * no-PHP option is configured.
+ */
+ if (!CHECK_FLAG(srp->sid.flags, ISIS_PREFIX_SID_NO_PHP)
+ || CHECK_FLAG(srp->sid.flags, ISIS_PREFIX_SID_EXPLICIT_NULL))
+ return -1;
+
+ sr_debug(" |- Installing Prefix-SID %pFX %s %u (%s) with nexthop self",
+ &srp->prefix, IS_SID_VALUE(srp->sid.flags) ? "label" : "index",
+ srp->sid.value, circuit_t2string(srn->level));
+
+ /* Compute input label and check that is valid. */
+ input_label = sr_prefix_in_label(srp);
+ if (input_label == MPLS_INVALID_LABEL)
+ return -1;
+
+ /* Update internal state. */
+ srp->input_label = input_label;
+ isis_sr_nexthop_update(&srp->u.local.info, MPLS_LABEL_IMPLICIT_NULL);
+
+ /* Install Prefix-SID in the forwarding plane. */
+ isis_zebra_send_prefix_sid(ZEBRA_MPLS_LABELS_REPLACE, srp);
+
+ return 0;
+}
+
+/**
+ * Process remote Prefix-SID and install it if possible. Input and Output
+ * labels are computed before installing them in LFIB.
+ *
+ * @param srp Segment Routing Prefix
+ *
+ * @return 0 on success, -1 otherwise
+ */
+static int sr_prefix_install_remote(struct sr_prefix *srp)
+{
+ const struct sr_node *srn = srp->srn;
+ struct isis_area *area = srn->area;
+ enum spf_tree_id tree_id;
+ struct listnode *node;
+ struct isis_nexthop *nexthop;
+ mpls_label_t input_label;
+ size_t nexthop_num = 0;
+
+ /* Lookup to associated IS-IS route. */
+ tree_id = (srp->prefix.family == AF_INET) ? SPFTREE_IPV4 : SPFTREE_IPV6;
+ srp->u.remote.rinfo = sr_prefix_lookup_route(area, tree_id, srp);
+ if (!srp->u.remote.rinfo)
+ /* SPF hasn't converged for this route yet. */
+ return -1;
+
+ /* Compute input label and check that is valid. */
+ input_label = sr_prefix_in_label(srp);
+ if (input_label == MPLS_INVALID_LABEL)
+ return -1;
+
+ sr_debug(" |- Installing Prefix-SID %pFX %s %u (%s)", &srp->prefix,
+ IS_SID_VALUE(srp->sid.flags) ? "label" : "index",
+ srp->sid.value, circuit_t2string(srn->level));
+
+ /* Process all SPF nexthops */
+ for (ALL_LIST_ELEMENTS_RO(srp->u.remote.rinfo->nexthops, node,
+ nexthop)) {
+ struct sr_node *srn_nexthop;
+ mpls_label_t output_label;
+
+ /* Check if the nexthop advertised a SRGB. */
+ srn_nexthop = sr_node_find(area, srn->level, nexthop->sysid);
+ if (!srn_nexthop)
+ goto next;
+
+ /*
+ * Check if the nexthop can handle SR-MPLS encapsulated IPv4 or
+ * IPv6 packets.
+ */
+ if ((nexthop->family == AF_INET
+ && !IS_SR_IPV4(srn_nexthop->cap.srgb))
+ || (nexthop->family == AF_INET6
+ && !IS_SR_IPV6(srn_nexthop->cap.srgb)))
+ goto next;
+
+ /* Compute output label and check if it is valid */
+ output_label =
+ sr_prefix_out_label(srp, srn_nexthop, nexthop->sysid);
+ if (output_label == MPLS_INVALID_LABEL)
+ goto next;
+
+ if (IS_DEBUG_ISIS(DEBUG_SR)) {
+ static char buf[INET6_ADDRSTRLEN];
+
+ inet_ntop(nexthop->family, &nexthop->ip, buf,
+ sizeof(buf));
+ zlog_debug(" |- nexthop %s label %u", buf,
+ output_label);
+ }
+
+ isis_sr_nexthop_update(&nexthop->sr, output_label);
+ nexthop_num++;
+ continue;
+ next:
+ isis_sr_nexthop_reset(&nexthop->sr);
+ }
+
+ /* Check that we found at least one valid nexthop */
+ if (nexthop_num == 0) {
+ sr_debug(" |- no valid nexthops");
+ return -1;
+ }
+
+ /* Update internal state. */
+ srp->input_label = input_label;
+
+ /* Install Prefix-SID in the forwarding plane. */
+ isis_zebra_send_prefix_sid(ZEBRA_MPLS_LABELS_REPLACE, srp);
+
+ return 0;
+}
+
+/**
+ * Process local or remote Prefix-SID and install it if possible.
+ *
+ * @param srp Segment Routing Prefix
+ */
+static void sr_prefix_install(struct sr_prefix *srp)
+{
+ const struct sr_node *srn = srp->srn;
+ struct isis_area *area = srn->area;
+ int ret;
+
+ sr_debug("ISIS-Sr (%s): Install Prefix-SID %pFX %s %u", area->area_tag,
+ &srp->prefix, IS_SID_VALUE(srp->sid.flags) ? "label" : "index",
+ srp->sid.value);
+
+ /* L1 routes are preferred over the L2 ones. */
+ if (area->is_type == IS_LEVEL_1_AND_2) {
+ struct sr_prefix *srp_l1, *srp_l2;
+
+ switch (srn->level) {
+ case ISIS_LEVEL1:
+ srp_l2 = sr_prefix_find_by_area(area, ISIS_LEVEL2,
+ &srp->prefix);
+ if (srp_l2)
+ sr_prefix_uninstall(srp_l2);
+ break;
+ case ISIS_LEVEL2:
+ srp_l1 = sr_prefix_find_by_area(area, ISIS_LEVEL1,
+ &srp->prefix);
+ if (srp_l1)
+ return;
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* Install corresponding LFIB entry */
+ if (srp->type == ISIS_SR_PREFIX_LOCAL)
+ ret = sr_prefix_install_local(srp);
+ else
+ ret = sr_prefix_install_remote(srp);
+ if (ret != 0)
+ sr_prefix_uninstall(srp);
+}
+
+/**
+ * Uninstall local or remote Prefix-SID.
+ *
+ * @param srp Segment Routing Prefix
+ */
+static void sr_prefix_uninstall(struct sr_prefix *srp)
+{
+ struct listnode *node;
+ struct isis_nexthop *nexthop;
+
+ /* Check that Input Label is valid */
+ if (srp->input_label == MPLS_INVALID_LABEL)
+ return;
+
+ sr_debug("ISIS-Sr: Un-install Prefix-SID %pFX %s %u", &srp->prefix,
+ IS_SID_VALUE(srp->sid.flags) ? "label" : "index",
+ srp->sid.value);
+
+ /* Uninstall Prefix-SID from the forwarding plane. */
+ isis_zebra_send_prefix_sid(ZEBRA_MPLS_LABELS_DELETE, srp);
+
+ /* Reset internal state. */
+ srp->input_label = MPLS_INVALID_LABEL;
+ switch (srp->type) {
+ case ISIS_SR_PREFIX_LOCAL:
+ isis_sr_nexthop_reset(&srp->u.local.info);
+ break;
+ case ISIS_SR_PREFIX_REMOTE:
+ if (srp->u.remote.rinfo) {
+ for (ALL_LIST_ELEMENTS_RO(srp->u.remote.rinfo->nexthops,
+ node, nexthop))
+ isis_sr_nexthop_reset(&nexthop->sr);
+ }
+ break;
+ }
+}
+
+/**
+ * Reinstall local or remote Prefix-SID.
+ *
+ * @param srp Segment Routing Prefix
+ */
+static inline void sr_prefix_reinstall(struct sr_prefix *srp,
+ bool make_before_break)
+{
+ /*
+ * Make Before Break can be used only when we know for sure that
+ * the Prefix-SID input label hasn't changed. Otherwise we need to
+ * uninstall the Prefix-SID first using the old input label before
+ * reinstalling it.
+ */
+ if (!make_before_break)
+ sr_prefix_uninstall(srp);
+
+ /* New input label is computed in sr_prefix_install() function */
+ sr_prefix_install(srp);
+}
+
+/* --- IS-IS LSP Parse functions -------------------------------------------- */
+
+/**
+ * Parse all SR-related information from the given Router Capabilities TLV.
+ *
+ * @param area IS-IS area
+ * @param level IS-IS level
+ * @param sysid System ID of the LSP
+ * @param router_cap Router Capability subTLVs
+ *
+ * @return Segment Routing Node structure for this System ID
+ */
+static struct sr_node *
+parse_router_cap_tlv(struct isis_area *area, int level, const uint8_t *sysid,
+ const struct isis_router_cap *router_cap)
+{
+ struct sr_node *srn;
+
+ if (!router_cap || router_cap->srgb.range_size == 0)
+ return NULL;
+
+ sr_debug("ISIS-Sr (%s): Parse Router Capability TLV", area->area_tag);
+
+ srn = sr_node_find(area, level, sysid);
+ if (srn) {
+ if (memcmp(&srn->cap, router_cap, sizeof(srn->cap)) != 0) {
+ srn->cap = *router_cap;
+ srn->state = SRDB_STATE_MODIFIED;
+ } else
+ srn->state = SRDB_STATE_UNCHANGED;
+ sr_debug(" |- Found %s SR Node %s",
+ srn->state == SRDB_STATE_MODIFIED ? "Modified"
+ : "Unchanged",
+ sysid_print(srn->sysid));
+ } else {
+ srn = sr_node_add(area, level, sysid, router_cap);
+ srn->state = SRDB_STATE_NEW;
+ }
+
+ return srn;
+}
+
+/**
+ * Parse list of Prefix-SID Sub-TLVs.
+ *
+ * @param srn Segment Routing Node
+ * @param prefix Prefix to be parsed
+ * @param local True if prefix comes from own LSP, false otherwise
+ * @param prefix_sids Prefix SID subTLVs
+ */
+static void parse_prefix_sid_subtlvs(struct sr_node *srn,
+ union prefixconstptr prefix, bool local,
+ struct isis_item_list *prefix_sids)
+{
+ struct isis_area *area = srn->area;
+ struct isis_item *i;
+
+ sr_debug("ISIS-Sr (%s): Parse Prefix SID TLV", area->area_tag);
+
+ /* Parse list of Prefix SID subTLVs */
+ for (i = prefix_sids->head; i; i = i->next) {
+ struct isis_prefix_sid *psid = (struct isis_prefix_sid *)i;
+ struct sr_prefix *srp;
+
+ /* Only SPF algorithm is supported right now */
+ if (psid->algorithm != SR_ALGORITHM_SPF)
+ continue;
+
+ /* Compute corresponding Segment Routing Prefix */
+ srp = sr_prefix_find_by_node(srn, prefix);
+ if (srp) {
+ if (srp->sid.flags != psid->flags
+ || srp->sid.algorithm != psid->algorithm
+ || srp->sid.value != psid->value) {
+ srp->sid = *psid;
+ srp->state = SRDB_STATE_MODIFIED;
+ } else
+ srp->state = SRDB_STATE_UNCHANGED;
+ sr_debug(" |- Found %s Prefix-SID %pFX",
+ srp->state == SRDB_STATE_MODIFIED
+ ? "Modified"
+ : "Unchanged",
+ &srp->prefix);
+
+ } else {
+ srp = sr_prefix_add(area, srn, prefix, local, psid);
+ srp->state = SRDB_STATE_NEW;
+ }
+ /*
+ * Stop the Prefix-SID iteration since we only support the SPF
+ * algorithm for now.
+ */
+ break;
+ }
+}
+
+/**
+ * Parse all SR-related information from the given LSP.
+ *
+ * @param area IS-IS area
+ * @param level IS-IS level
+ * @param srn Segment Routing Node
+ * @param lsp IS-IS LSP
+ */
+static void parse_lsp(struct isis_area *area, int level, struct sr_node **srn,
+ struct isis_lsp *lsp)
+{
+ struct isis_item_list *items;
+ struct isis_item *i;
+ bool local = lsp->own_lsp;
+
+ /* Check LSP sequence number */
+ if (lsp->hdr.seqno == 0) {
+ zlog_warn("%s: lsp with 0 seq_num - ignore", __func__);
+ return;
+ }
+
+ sr_debug("ISIS-Sr (%s): Parse LSP from node %s", area->area_tag,
+ sysid_print(lsp->hdr.lsp_id));
+
+ /* Parse the Router Capability TLV. */
+ if (*srn == NULL) {
+ *srn = parse_router_cap_tlv(area, level, lsp->hdr.lsp_id,
+ lsp->tlvs->router_cap);
+ if (!*srn)
+ return;
+ }
+
+ /* Parse the Extended IP Reachability TLV. */
+ items = &lsp->tlvs->extended_ip_reach;
+ for (i = items->head; i; i = i->next) {
+ struct isis_extended_ip_reach *ir;
+
+ ir = (struct isis_extended_ip_reach *)i;
+ if (!ir->subtlvs)
+ continue;
+
+ parse_prefix_sid_subtlvs(*srn, &ir->prefix, local,
+ &ir->subtlvs->prefix_sids);
+ }
+
+ /* Parse Multi Topology Reachable IPv6 Prefixes TLV. */
+ items = isis_lookup_mt_items(&lsp->tlvs->mt_ipv6_reach,
+ ISIS_MT_IPV6_UNICAST);
+ for (i = items ? items->head : NULL; i; i = i->next) {
+ struct isis_ipv6_reach *ir;
+
+ ir = (struct isis_ipv6_reach *)i;
+ if (!ir->subtlvs)
+ continue;
+
+ parse_prefix_sid_subtlvs(*srn, &ir->prefix, local,
+ &ir->subtlvs->prefix_sids);
+ }
+}
+
+/**
+ * Parse all SR-related information from the entire LSPDB.
+ *
+ * @param area IS-IS area
+ */
+static void parse_lspdb(struct isis_area *area)
+{
+ struct isis_lsp *lsp;
+
+ sr_debug("ISIS-Sr (%s): Parse LSP Data Base", area->area_tag);
+
+ /* Process all LSP from Level 1 & 2 */
+ for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
+ frr_each (lspdb, &area->lspdb[level - 1], lsp) {
+ struct isis_lsp *frag;
+ struct listnode *node;
+ struct sr_node *srn = NULL;
+
+ /* Skip Pseudo ID LSP and LSP without TLVs */
+ if (LSP_PSEUDO_ID(lsp->hdr.lsp_id))
+ continue;
+ if (!lsp->tlvs)
+ continue;
+
+ /* Parse LSP, then fragment */
+ parse_lsp(area, level, &srn, lsp);
+ for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag))
+ parse_lsp(area, level, &srn, frag);
+ }
+ }
+}
+
+/**
+ * Process any new/deleted/modified Prefix-SID in the LSPDB.
+ *
+ * @param srn Segment Routing Node
+ * @param srp Segment Routing Prefix
+ */
+static void process_prefix_changes(struct sr_node *srn, struct sr_prefix *srp)
+{
+ struct isis_area *area = srn->area;
+
+ /* Install/reinstall/uninstall Prefix-SID if necessary. */
+ switch (srp->state) {
+ case SRDB_STATE_NEW:
+ sr_debug("ISIS-Sr (%s): Created Prefix-SID %pFX for SR node %s",
+ area->area_tag, &srp->prefix, sysid_print(srn->sysid));
+ sr_prefix_install(srp);
+ break;
+ case SRDB_STATE_MODIFIED:
+ sr_debug(
+ "ISIS-Sr (%s): Modified Prefix-SID %pFX for SR node %s",
+ area->area_tag, &srp->prefix, sysid_print(srn->sysid));
+ sr_prefix_reinstall(srp, false);
+ break;
+ case SRDB_STATE_UNCHANGED:
+ break;
+ default:
+ sr_debug("ISIS-Sr (%s): Removed Prefix-SID %pFX for SR node %s",
+ area->area_tag, &srp->prefix, sysid_print(srn->sysid));
+ sr_prefix_del(area, srn, srp);
+ return;
+ }
+
+ /* Validate SRDB State for next LSPDB parsing */
+ srp->state = SRDB_STATE_VALIDATED;
+}
+
+/**
+ * Process any new/deleted/modified SRGB in the LSPDB.
+ *
+ * @param area IS-IS area
+ * @param level IS-IS level
+ * @param srn Segment Routing Node
+ */
+static void process_node_changes(struct isis_area *area, int level,
+ struct sr_node *srn)
+{
+ struct sr_prefix *srp;
+ uint8_t sysid[ISIS_SYS_ID_LEN];
+ bool adjacent;
+
+ memcpy(sysid, srn->sysid, sizeof(sysid));
+
+ /*
+ * If an neighbor router's SRGB was changed or created, then reinstall
+ * all Prefix-SIDs from all nodes that use this neighbor as nexthop.
+ */
+ adjacent = isis_adj_exists(area, level, sysid);
+ switch (srn->state) {
+ case SRDB_STATE_NEW:
+ case SRDB_STATE_MODIFIED:
+ sr_debug("ISIS-Sr (%s): Create/Update SR node %s",
+ area->area_tag, sysid_print(srn->sysid));
+ if (adjacent)
+ sr_node_srgb_update(area, level, sysid);
+ break;
+ case SRDB_STATE_UNCHANGED:
+ break;
+ default:
+ /* SR capabilities have been removed. Delete SR-Node */
+ sr_debug("ISIS-Sr (%s): Remove SR node %s", area->area_tag,
+ sysid_print(srn->sysid));
+
+ sr_node_del(area, level, srn);
+ /* and Update remaining Prefix-SID from all remaining SR Node */
+ if (adjacent)
+ sr_node_srgb_update(area, level, sysid);
+ return;
+ }
+
+ /* Validate SRDB State for next LSPDB parsing */
+ srn->state = SRDB_STATE_VALIDATED;
+
+ /* Finally, process all Prefix-SID of this SR Node */
+ frr_each_safe (srdb_node_prefix, &srn->prefix_sids, srp)
+ process_prefix_changes(srn, srp);
+}
+
+/**
+ * Parse and process all SR-related Sub-TLVs after running the SPF algorithm.
+ *
+ * @param area IS-IS area
+ */
+void isis_area_verify_sr(struct isis_area *area)
+{
+ struct sr_node *srn;
+
+ if (!area->srdb.enabled)
+ return;
+
+ /* Parse LSPDB to detect new/deleted/modified SR (sub-)TLVs. */
+ parse_lspdb(area);
+
+ /* Process possible SR-related changes in the LDPSB. */
+ for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
+ frr_each_safe (srdb_node, &area->srdb.sr_nodes[level - 1], srn)
+ process_node_changes(area, level, srn);
+ }
+}
+
+/**
+ * Once a route is updated in the SPT, reinstall or uninstall its corresponding
+ * Prefix-SID (if any).
+ *
+ * @param area IS-IS area
+ * @param prefix Prefix to be updated
+ * @param route_info New Route Information
+ *
+ * @return 0
+ */
+static int sr_route_update(struct isis_area *area, struct prefix *prefix,
+ struct isis_route_info *route_info)
+{
+ struct sr_prefix *srp;
+
+ if (!area->srdb.enabled)
+ return 0;
+
+ sr_debug("ISIS-Sr (%s): Update route for prefix %pFX", area->area_tag,
+ prefix);
+
+ /* Lookup to Segment Routing Prefix for this prefix */
+ switch (area->is_type) {
+ case IS_LEVEL_1:
+ srp = sr_prefix_find_by_area(area, ISIS_LEVEL1, prefix);
+ break;
+ case IS_LEVEL_2:
+ srp = sr_prefix_find_by_area(area, ISIS_LEVEL2, prefix);
+ break;
+ case IS_LEVEL_1_AND_2:
+ srp = sr_prefix_find_by_area(area, ISIS_LEVEL1, prefix);
+ if (!srp)
+ srp = sr_prefix_find_by_area(area, ISIS_LEVEL2, prefix);
+ break;
+ default:
+ flog_err(EC_LIB_DEVELOPMENT, "%s: unknown area level",
+ __func__);
+ exit(1);
+ }
+
+ /* Skip NULL or local Segment Routing Prefix */
+ if (!srp || srp->type == ISIS_SR_PREFIX_LOCAL)
+ return 0;
+
+ /* Install or unintall Prefix-SID if route is Active or not */
+ if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ACTIVE)) {
+ /*
+ * The Prefix-SID input label hasn't changed. We could use the
+ * "Make Before Break" option. Zebra layer will update output
+ * label by adding new label(s) before removing old one(s).
+ */
+ sr_prefix_reinstall(srp, true);
+ srp->u.remote.rinfo = route_info;
+ } else {
+ sr_prefix_uninstall(srp);
+ srp->u.remote.rinfo = NULL;
+ }
+
+ return 0;
+}
+
+/* --- Segment Routing Adjacency-SID management functions ------------------- */
+
+/**
+ * Add new local Adjacency-SID.
+ *
+ * @param adj IS-IS Adjacency
+ * @param family Inet Family (IPv4 or IPv6)
+ * @param backup True to initialize backup Adjacency SID
+ */
+static void sr_adj_sid_add_single(struct isis_adjacency *adj, int family,
+ bool backup)
+{
+ struct isis_circuit *circuit = adj->circuit;
+ struct isis_area *area = circuit->area;
+ struct sr_adjacency *sra;
+ struct isis_adj_sid *adj_sid;
+ struct isis_lan_adj_sid *ladj_sid;
+ union g_addr nexthop = {};
+ uint8_t flags;
+ mpls_label_t input_label;
+
+ sr_debug("ISIS-Sr (%s): Add %s Adjacency SID", area->area_tag,
+ backup ? "Backup" : "Primary");
+
+ /* Determine nexthop IP address */
+ switch (family) {
+ case AF_INET:
+ if (!circuit->ip_router)
+ return;
+
+ nexthop.ipv4 = adj->ipv4_addresses[0];
+ break;
+ case AF_INET6:
+ if (!circuit->ipv6_router)
+ return;
+
+ nexthop.ipv6 = adj->ipv6_addresses[0];
+ break;
+ default:
+ flog_err(EC_LIB_DEVELOPMENT,
+ "%s: unexpected address-family: %u", __func__, family);
+ exit(1);
+ }
+
+ /* Prepare Segment Routing Adjacency as per RFC8667 section #2.2 */
+ flags = EXT_SUBTLV_LINK_ADJ_SID_VFLG | EXT_SUBTLV_LINK_ADJ_SID_LFLG;
+ if (family == AF_INET6)
+ SET_FLAG(flags, EXT_SUBTLV_LINK_ADJ_SID_FFLG);
+ if (backup)
+ SET_FLAG(flags, EXT_SUBTLV_LINK_ADJ_SID_BFLG);
+
+ input_label = isis_zebra_request_dynamic_label();
+ if (circuit->ext == NULL)
+ circuit->ext = isis_alloc_ext_subtlvs();
+
+ sra = XCALLOC(MTYPE_ISIS_SR_INFO, sizeof(*sra));
+ sra->type = backup ? ISIS_SR_LAN_BACKUP : ISIS_SR_ADJ_NORMAL;
+ sra->nexthop.family = family;
+ sra->nexthop.address = nexthop;
+ sra->nexthop.label = input_label;
+ switch (circuit->circ_type) {
+ /* LAN Adjacency-SID for Broadcast interface section #2.2.2 */
+ case CIRCUIT_T_BROADCAST:
+ ladj_sid = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*ladj_sid));
+ ladj_sid->family = family;
+ ladj_sid->flags = flags;
+ ladj_sid->weight = 0;
+ memcpy(ladj_sid->neighbor_id, adj->sysid,
+ sizeof(ladj_sid->neighbor_id));
+ ladj_sid->sid = input_label;
+ isis_tlvs_add_lan_adj_sid(circuit->ext, ladj_sid);
+ sra->u.ladj_sid = ladj_sid;
+ break;
+ /* Adjacency-SID for Point to Point interface section #2.2.1 */
+ case CIRCUIT_T_P2P:
+ adj_sid = XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*adj_sid));
+ adj_sid->family = family;
+ adj_sid->flags = flags;
+ adj_sid->weight = 0;
+ adj_sid->sid = input_label;
+ isis_tlvs_add_adj_sid(circuit->ext, adj_sid);
+ sra->u.adj_sid = adj_sid;
+ break;
+ default:
+ flog_err(EC_LIB_DEVELOPMENT, "%s: unexpected circuit type: %u",
+ __func__, circuit->circ_type);
+ exit(1);
+ }
+
+ /* Add Adjacency-SID in SRDB */
+ sra->adj = adj;
+ listnode_add(area->srdb.adj_sids, sra);
+ listnode_add(adj->adj_sids, sra);
+
+ isis_zebra_send_adjacency_sid(ZEBRA_MPLS_LABELS_ADD, sra);
+}
+
+/**
+ * Add Primary and Backup local Adjacency SID.
+ *
+ * @param adj IS-IS Adjacency
+ * @param family Inet Family (IPv4 or IPv6)
+ */
+static void sr_adj_sid_add(struct isis_adjacency *adj, int family)
+{
+ sr_adj_sid_add_single(adj, family, false);
+ sr_adj_sid_add_single(adj, family, true);
+}
+
+/**
+ * Delete local Adj-SID.
+ *
+ * @param sra Segment Routing Adjacency
+ */
+static void sr_adj_sid_del(struct sr_adjacency *sra)
+{
+ struct isis_circuit *circuit = sra->adj->circuit;
+ struct isis_area *area = circuit->area;
+
+ sr_debug("ISIS-Sr (%s): Delete Adjacency SID", area->area_tag);
+
+ isis_zebra_send_adjacency_sid(ZEBRA_MPLS_LABELS_DELETE, sra);
+
+ /* Release dynamic label and remove subTLVs */
+ switch (circuit->circ_type) {
+ case CIRCUIT_T_BROADCAST:
+ isis_zebra_release_dynamic_label(sra->u.ladj_sid->sid);
+ isis_tlvs_del_lan_adj_sid(circuit->ext, sra->u.ladj_sid);
+ break;
+ case CIRCUIT_T_P2P:
+ isis_zebra_release_dynamic_label(sra->u.adj_sid->sid);
+ isis_tlvs_del_adj_sid(circuit->ext, sra->u.adj_sid);
+ break;
+ default:
+ flog_err(EC_LIB_DEVELOPMENT, "%s: unexpected circuit type: %u",
+ __func__, circuit->circ_type);
+ exit(1);
+ }
+
+ /* Remove Adjacency-SID from the SRDB */
+ listnode_delete(area->srdb.adj_sids, sra);
+ listnode_delete(sra->adj->adj_sids, sra);
+ XFREE(MTYPE_ISIS_SR_INFO, sra);
+}
+
+/**
+ * Remove all Adjacency-SIDs associated to an adjacency that is going down.
+ *
+ * @param adj IS-IS Adjacency
+ *
+ * @return 0
+ */
+static int sr_adj_state_change(struct isis_adjacency *adj)
+{
+ struct sr_adjacency *sra;
+ struct listnode *node, *nnode;
+
+ if (!adj->circuit->area->srdb.enabled)
+ return 0;
+
+ if (adj->adj_state == ISIS_ADJ_UP)
+ return 0;
+
+ for (ALL_LIST_ELEMENTS(adj->adj_sids, node, nnode, sra))
+ sr_adj_sid_del(sra);
+
+ return 0;
+}
+
+/**
+ * When IS-IS Adjacency got one or more IPv4/IPv6 addresses, add new IPv4 or
+ * IPv6 address to corresponding Adjacency-SID accordingly.
+ *
+ * @param adj IS-IS Adjacency
+ * @param family Inet Family (IPv4 or IPv6)
+ *
+ * @return 0
+ */
+static int sr_adj_ip_enabled(struct isis_adjacency *adj, int family)
+{
+ if (!adj->circuit->area->srdb.enabled)
+ return 0;
+
+ sr_adj_sid_add(adj, family);
+
+ return 0;
+}
+
+/**
+ * When IS-IS Adjacency doesn't have any IPv4 or IPv6 addresses anymore,
+ * delete the corresponding Adjacency-SID(s) accordingly.
+ *
+ * @param adj IS-IS Adjacency
+ * @param family Inet Family (IPv4 or IPv6)
+ *
+ * @return 0
+ */
+static int sr_adj_ip_disabled(struct isis_adjacency *adj, int family)
+{
+ struct sr_adjacency *sra;
+ struct listnode *node, *nnode;
+
+ if (!adj->circuit->area->srdb.enabled)
+ return 0;
+
+ for (ALL_LIST_ELEMENTS(adj->adj_sids, node, nnode, sra))
+ if (sra->nexthop.family == family)
+ sr_adj_sid_del(sra);
+
+ return 0;
+}
+
+/**
+ * Activate local Prefix-SID when loopback interface goes up for IS-IS.
+ *
+ * @param ifp Loopback Interface
+ *
+ * @return 0
+ */
+static int sr_if_new_hook(struct interface *ifp)
+{
+ struct isis_circuit *circuit;
+ struct isis_area *area;
+ struct connected *connected;
+ struct listnode *node;
+
+ /* Get corresponding circuit */
+ circuit = circuit_scan_by_ifp(ifp);
+ if (!circuit)
+ return 0;
+
+ area = circuit->area;
+ if (!area)
+ return 0;
+
+ /*
+ * Update the Node-SID flag of the configured Prefix-SID mappings if
+ * necessary. This needs to be done here since isisd reads the startup
+ * configuration before receiving interface information from zebra.
+ */
+ FOR_ALL_INTERFACES_ADDRESSES (ifp, connected, node) {
+ struct sr_prefix_cfg *pcfg;
+
+ pcfg = isis_sr_cfg_prefix_find(area, connected->address);
+ if (!pcfg)
+ continue;
+
+ if (sr_prefix_is_node_sid(ifp, &pcfg->prefix)
+ && !pcfg->node_sid) {
+ pcfg->node_sid = true;
+ lsp_regenerate_schedule(area, area->is_type, 0);
+ }
+ }
+
+ return 0;
+}
+
+/* --- Segment Routing Show information functions --------------------------- */
+
+/**
+ * Show LFIB operation in human readable format.
+ *
+ * @param buf Buffer to store string output. Must be pre-allocate
+ * @param size Size of the buffer
+ * @param label_in Input Label
+ * @param label_out Output Label
+ *
+ * @return String containing LFIB operation in human readable format
+ */
+static char *sr_op2str(char *buf, size_t size, mpls_label_t label_in,
+ mpls_label_t label_out)
+{
+ if (size < 24)
+ return NULL;
+
+ if (label_in == MPLS_INVALID_LABEL) {
+ snprintf(buf, size, "no-op.");
+ return buf;
+ }
+
+ switch (label_out) {
+ case MPLS_LABEL_IMPLICIT_NULL:
+ snprintf(buf, size, "Pop(%u)", label_in);
+ break;
+ case MPLS_LABEL_IPV4_EXPLICIT_NULL:
+ case MPLS_LABEL_IPV6_EXPLICIT_NULL:
+ snprintf(buf, size, "Swap(%u, null)", label_in);
+ break;
+ case MPLS_INVALID_LABEL:
+ snprintf(buf, size, "no-op.");
+ break;
+ default:
+ snprintf(buf, size, "Swap(%u, %u)", label_in, label_out);
+ break;
+ }
+ return buf;
+}
+
+/**
+ * Show Local Prefix-SID.
+ *
+ * @param vty VTY output
+ * @param tt Table format
+ * @param area IS-IS area
+ * @param srp Segment Routing Prefix
+ */
+static void show_prefix_sid_local(struct vty *vty, struct ttable *tt,
+ const struct isis_area *area,
+ const struct sr_prefix *srp)
+{
+ const struct sr_nexthop_info *srnh = &srp->u.local.info;
+ char buf_prefix[BUFSIZ];
+ char buf_oper[BUFSIZ];
+ char buf_iface[BUFSIZ];
+ char buf_uptime[BUFSIZ];
+
+ if (srnh->label != MPLS_INVALID_LABEL) {
+ struct interface *ifp;
+ ifp = if_lookup_prefix(&srp->prefix, VRF_DEFAULT);
+ if (ifp)
+ strlcpy(buf_iface, ifp->name, sizeof(buf_iface));
+ else
+ snprintf(buf_iface, sizeof(buf_iface), "-");
+ log_uptime(srnh->uptime, buf_uptime, sizeof(buf_uptime));
+ } else {
+ snprintf(buf_iface, sizeof(buf_iface), "-");
+ snprintf(buf_uptime, sizeof(buf_uptime), "-");
+ }
+ sr_op2str(buf_oper, sizeof(buf_oper), srp->input_label,
+ MPLS_LABEL_IMPLICIT_NULL);
+
+ ttable_add_row(tt, "%s|%u|%s|-|%s|%s",
+ prefix2str(&srp->prefix, buf_prefix, sizeof(buf_prefix)),
+ srp->sid.value, buf_oper, buf_iface, buf_uptime);
+}
+
+/**
+ * Show Remote Prefix-SID.
+ *
+ * @param vty VTY output
+ * @param tt Table format
+ * @param area IS-IS area
+ * @param srp Segment Routing Prefix
+ */
+static void show_prefix_sid_remote(struct vty *vty, struct ttable *tt,
+ const struct isis_area *area,
+ const struct sr_prefix *srp)
+{
+ struct isis_nexthop *nexthop;
+ struct listnode *node;
+ char buf_prefix[BUFSIZ];
+ char buf_oper[BUFSIZ];
+ char buf_nhop[BUFSIZ];
+ char buf_iface[BUFSIZ];
+ char buf_uptime[BUFSIZ];
+ bool first = true;
+
+ (void)prefix2str(&srp->prefix, buf_prefix, sizeof(buf_prefix));
+
+ if (!srp->u.remote.rinfo) {
+ ttable_add_row(tt, "%s|%u|%s|-|-|-", buf_prefix, srp->sid.value,
+ sr_op2str(buf_oper, sizeof(buf_oper),
+ srp->input_label,
+ MPLS_LABEL_IMPLICIT_NULL));
+ return;
+ }
+
+ for (ALL_LIST_ELEMENTS_RO(srp->u.remote.rinfo->nexthops, node,
+ nexthop)) {
+ struct interface *ifp;
+
+ inet_ntop(nexthop->family, &nexthop->ip, buf_nhop,
+ sizeof(buf_nhop));
+ ifp = if_lookup_by_index(nexthop->ifindex, VRF_DEFAULT);
+ if (ifp)
+ strlcpy(buf_iface, ifp->name, sizeof(buf_iface));
+ else
+ snprintf(buf_iface, sizeof(buf_iface), "ifindex %u",
+ nexthop->ifindex);
+ if (nexthop->sr.label == MPLS_INVALID_LABEL)
+ snprintf(buf_uptime, sizeof(buf_uptime), "-");
+ else
+ log_uptime(nexthop->sr.uptime, buf_uptime,
+ sizeof(buf_uptime));
+ sr_op2str(buf_oper, sizeof(buf_oper), srp->input_label,
+ nexthop->sr.label);
+
+ if (first)
+ ttable_add_row(tt, "%s|%u|%s|%s|%s|%s", buf_prefix,
+ srp->sid.value, buf_oper, buf_nhop,
+ buf_iface, buf_uptime);
+ else
+ ttable_add_row(tt, "|||%s|%s|%s|%s", buf_oper, buf_nhop,
+ buf_iface, buf_uptime);
+ first = false;
+ }
+}
+
+/**
+ * Show Prefix-SIDs.
+ *
+ * @param vty VTY output
+ * @param area IS-IS area
+ * @param level IS-IS level
+ */
+static void show_prefix_sids(struct vty *vty, struct isis_area *area, int level)
+{
+ struct sr_prefix *srp;
+ struct ttable *tt;
+
+ if (srdb_area_prefix_count(&area->srdb.prefix_sids[level - 1]) == 0)
+ return;
+
+ vty_out(vty, " IS-IS %s Prefix-SIDs:\n\n", circuit_t2string(level));
+
+ /* Prepare table. */
+ tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+ ttable_add_row(tt, "Prefix|SID|Label Op.|Nexthop|Interface|Uptime");
+ tt->style.cell.rpad = 2;
+ tt->style.corner = '+';
+ ttable_restyle(tt);
+ ttable_rowseps(tt, 0, BOTTOM, true, '-');
+
+ /* Process all Prefix-SID from the SRDB */
+ frr_each (srdb_area_prefix, &area->srdb.prefix_sids[level - 1], srp) {
+ switch (srp->type) {
+ case ISIS_SR_PREFIX_LOCAL:
+ show_prefix_sid_local(vty, tt, area, srp);
+ break;
+ case ISIS_SR_PREFIX_REMOTE:
+ show_prefix_sid_remote(vty, tt, area, srp);
+ break;
+ }
+ }
+
+ /* Dump the generated table. */
+ if (tt->nrows > 1) {
+ char *table;
+
+ table = ttable_dump(tt, "\n");
+ vty_out(vty, "%s\n", table);
+ XFREE(MTYPE_TMP, table);
+ }
+ ttable_del(tt);
+}
+
+/**
+ * Declaration of new show commands.
+ */
+DEFUN(show_sr_prefix_sids, show_sr_prefix_sids_cmd,
+ "show isis segment-routing prefix-sids",
+ SHOW_STR PROTO_HELP
+ "Segment-Routing\n"
+ "Segment-Routing Prefix-SIDs\n")
+{
+ struct listnode *node;
+ struct isis_area *area;
+
+ for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
+ vty_out(vty, "Area %s:\n",
+ area->area_tag ? area->area_tag : "null");
+
+ for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++)
+ show_prefix_sids(vty, area, level);
+ }
+
+ return CMD_SUCCESS;
+}
+
+/**
+ * Show Segment Routing Node.
+ *
+ * @param vty VTY output
+ * @param area IS-IS area
+ * @param level IS-IS level
+ */
+static void show_node(struct vty *vty, struct isis_area *area, int level)
+{
+ struct sr_node *srn;
+ struct ttable *tt;
+
+ if (srdb_area_prefix_count(&area->srdb.prefix_sids[level - 1]) == 0)
+ return;
+
+ vty_out(vty, " IS-IS %s SR-Node:\n\n", circuit_t2string(level));
+
+ /* Prepare table. */
+ tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]);
+ ttable_add_row(tt, "System ID|SRGB|Algorithm|MSD");
+ tt->style.cell.rpad = 2;
+ tt->style.corner = '+';
+ ttable_restyle(tt);
+ ttable_rowseps(tt, 0, BOTTOM, true, '-');
+
+ /* Process all SR-Node from the SRDB */
+ frr_each (srdb_node, &area->srdb.sr_nodes[level - 1], srn) {
+ ttable_add_row(tt, "%s|%u - %u|%s|%u", sysid_print(srn->sysid),
+ srn->cap.srgb.lower_bound,
+ srn->cap.srgb.lower_bound
+ + srn->cap.srgb.range_size - 1,
+ srn->cap.algo[0] == SR_ALGORITHM_SPF ? "SPF"
+ : "S-SPF",
+ srn->cap.msd);
+ }
+
+ /* Dump the generated table. */
+ if (tt->nrows > 1) {
+ char *table;
+
+ table = ttable_dump(tt, "\n");
+ vty_out(vty, "%s\n", table);
+ XFREE(MTYPE_TMP, table);
+ }
+ ttable_del(tt);
+}
+
+DEFUN(show_sr_node, show_sr_node_cmd,
+ "show isis segment-routing node",
+ SHOW_STR PROTO_HELP
+ "Segment-Routing\n"
+ "Segment-Routing node\n")
+{
+ struct listnode *node;
+ struct isis_area *area;
+
+ for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) {
+ vty_out(vty, "Area %s:\n",
+ area->area_tag ? area->area_tag : "null");
+
+ for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++)
+ show_node(vty, area, level);
+ }
+
+ return CMD_SUCCESS;
+}
+
+
+/* --- IS-IS Segment Routing Management function ---------------------------- */
+
+/**
+ * Enable SR on the given IS-IS area.
+ *
+ * @param area IS-IS area
+ *
+ * @return 0 on success, -1 otherwise
+ */
+int isis_sr_start(struct isis_area *area)
+{
+ struct isis_sr_db *srdb = &area->srdb;
+ struct isis_circuit *circuit;
+ struct listnode *node;
+
+ /*
+ * Request SGRB to the label manager. If the allocation fails, return
+ * an error to disable SR until a new SRGB is successfully allocated.
+ */
+ if (isis_zebra_request_label_range(
+ srdb->config.srgb_lower_bound,
+ srdb->config.srgb_upper_bound
+ - srdb->config.srgb_lower_bound + 1))
+ return -1;
+
+ sr_debug("ISIS-Sr: Starting Segment Routing for area %s",
+ area->area_tag);
+
+ /* Create Adjacency-SIDs from existing IS-IS Adjacencies. */
+ for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
+ struct isis_adjacency *adj;
+ struct listnode *anode;
+
+ switch (circuit->circ_type) {
+ case CIRCUIT_T_BROADCAST:
+ for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS;
+ level++) {
+ for (ALL_LIST_ELEMENTS_RO(
+ circuit->u.bc.adjdb[level - 1],
+ anode, adj)) {
+ if (adj->ipv4_address_count > 0)
+ sr_adj_sid_add(adj, AF_INET);
+ if (adj->ipv6_address_count > 0)
+ sr_adj_sid_add(adj, AF_INET6);
+ }
+ }
+ break;
+ case CIRCUIT_T_P2P:
+ adj = circuit->u.p2p.neighbor;
+ if (adj && adj->ipv4_address_count > 0)
+ sr_adj_sid_add(adj, AF_INET);
+ if (adj && adj->ipv6_address_count > 0)
+ sr_adj_sid_add(adj, AF_INET6);
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* Regenerate LSPs to advertise Segment Routing capabilities. */
+ lsp_regenerate_schedule(area, area->is_type, 0);
+
+ return 0;
+}
+
+/**
+ * Disable SR on the given IS-IS area.
+ *
+ * @param area IS-IS area
+ */
+void isis_sr_stop(struct isis_area *area)
+{
+ struct isis_sr_db *srdb = &area->srdb;
+ struct sr_adjacency *sra;
+ struct listnode *node, *nnode;
+
+ sr_debug("ISIS-Sr: Stopping Segment Routing for area %s",
+ area->area_tag);
+
+ /* Uninstall all local Adjacency-SIDs. */
+ for (ALL_LIST_ELEMENTS(area->srdb.adj_sids, node, nnode, sra))
+ sr_adj_sid_del(sra);
+
+ /* Uninstall all Prefix-SIDs from all SR Node. */
+ for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
+ while (srdb_node_count(&srdb->sr_nodes[level - 1]) > 0) {
+ struct sr_node *srn;
+
+ srn = srdb_node_first(&srdb->sr_nodes[level - 1]);
+ sr_node_del(area, level, srn);
+ }
+ }
+
+ /* Release SRGB. */
+ isis_zebra_release_label_range(srdb->config.srgb_lower_bound,
+ srdb->config.srgb_upper_bound);
+
+ /* Regenerate LSPs to advertise that the Node is no more SR enable. */
+ lsp_regenerate_schedule(area, area->is_type, 0);
+}
+
+/**
+ * IS-IS Segment Routing initialization for given area.
+ *
+ * @param area IS-IS area
+ */
+void isis_sr_area_init(struct isis_area *area)
+{
+ struct isis_sr_db *srdb = &area->srdb;
+
+ sr_debug("ISIS-Sr (%s): Initialize Segment Routing SRDB",
+ area->area_tag);
+
+ /* Initialize Segment Routing Data Base */
+ memset(srdb, 0, sizeof(*srdb));
+ srdb->enabled = false;
+ srdb->adj_sids = list_new();
+
+ for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) {
+ srdb_node_init(&srdb->sr_nodes[level - 1]);
+ srdb_area_prefix_init(&srdb->prefix_sids[level - 1]);
+ }
+
+ /* Pull defaults from the YANG module. */
+#ifndef FABRICD
+ srdb->config.enabled = yang_get_default_bool("%s/enabled", ISIS_SR);
+ srdb->config.srgb_lower_bound =
+ yang_get_default_uint32("%s/srgb/lower-bound", ISIS_SR);
+ srdb->config.srgb_upper_bound =
+ yang_get_default_uint32("%s/srgb/upper-bound", ISIS_SR);
+#else
+ srdb->config.enabled = false;
+ srdb->config.srgb_lower_bound = SRGB_LOWER_BOUND;
+ srdb->config.srgb_upper_bound = SRGB_UPPER_BOUND;
+#endif
+ srdb->config.msd = 0;
+ srdb_prefix_cfg_init(&srdb->config.prefix_sids);
+}
+
+/**
+ * Terminate IS-IS Segment Routing for the given area.
+ *
+ * @param area IS-IS area
+ */
+void isis_sr_area_term(struct isis_area *area)
+{
+ struct isis_sr_db *srdb = &area->srdb;
+
+ /* Stop Segment Routing */
+ if (area->srdb.enabled)
+ isis_sr_stop(area);
+
+ /* Clear Prefix-SID configuration. */
+ while (srdb_prefix_cfg_count(&srdb->config.prefix_sids) > 0) {
+ struct sr_prefix_cfg *pcfg;
+
+ pcfg = srdb_prefix_cfg_first(&srdb->config.prefix_sids);
+ isis_sr_cfg_prefix_del(pcfg);
+ }
+}
+
+/**
+ * IS-IS Segment Routing global initialization.
+ */
+void isis_sr_init(void)
+{
+ install_element(VIEW_NODE, &show_sr_prefix_sids_cmd);
+ install_element(VIEW_NODE, &show_sr_node_cmd);
+
+ /* Register hooks. */
+ hook_register(isis_adj_state_change_hook, sr_adj_state_change);
+ hook_register(isis_adj_ip_enabled_hook, sr_adj_ip_enabled);
+ hook_register(isis_adj_ip_disabled_hook, sr_adj_ip_disabled);
+ hook_register(isis_route_update_hook, sr_route_update);
+ hook_register(isis_if_new_hook, sr_if_new_hook);
+}
+
+/**
+ * IS-IS Segment Routing global terminate.
+ */
+void isis_sr_term(void)
+{
+ /* Unregister hooks. */
+ hook_unregister(isis_adj_state_change_hook, sr_adj_state_change);
+ hook_unregister(isis_adj_ip_enabled_hook, sr_adj_ip_enabled);
+ hook_unregister(isis_adj_ip_disabled_hook, sr_adj_ip_disabled);
+ hook_unregister(isis_route_update_hook, sr_route_update);
+ hook_unregister(isis_if_new_hook, sr_if_new_hook);
+}
diff --git a/isisd/isis_sr.h b/isisd/isis_sr.h
new file mode 100644
index 0000000000..dec329ab48
--- /dev/null
+++ b/isisd/isis_sr.h
@@ -0,0 +1,262 @@
+/*
+ * This is an implementation of Segment Routing for IS-IS as per RFC 8667
+ *
+ * Copyright (C) 2019 Orange http://www.orange.com
+ *
+ * Author: Olivier Dugeon <olivier.dugeon@orange.com>
+ * Contributor: Renato Westphal <renato@opensourcerouting.org> for NetDEF
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; see the file COPYING; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef _FRR_ISIS_SR_H
+#define _FRR_ISIS_SR_H
+
+#include "lib/linklist.h"
+#include "lib/mpls.h"
+#include "lib/nexthop.h"
+#include "lib/typesafe.h"
+
+#include "isisd/isis_tlvs.h"
+
+/*
+ * Segment Routing information is transported through the following Sub-TLVs:
+ *
+ * Sub-TLV Name Value TLVs
+ * ---------------------------------------------------------------------
+ * SID Label 1
+ *
+ * Prefix Segment Identifier 3 135, 235, 236 and 237
+ *
+ * Adjacency Segment Identifier 31 22, 23, 141, 222 and 223
+ * LAN Adjacency Segment Identifier 32 22, 23, 141, 222 and 223
+ *
+ * Segment Routing Capability 2 242
+ * Segment Routing Algorithm 19 242
+ * Node Maximum Stack Depth (MSD) 23 242
+ *
+ * Sub-TLV definitions, serialization and de-serialization are defined
+ * in isis_tlvs.[c,h].
+ */
+
+#define SRGB_LOWER_BOUND 16000
+#define SRGB_UPPER_BOUND 23999
+
+/* Segment Routing Data Base (SRDB) RB-Tree structure */
+PREDECL_RBTREE_UNIQ(srdb_node)
+PREDECL_RBTREE_UNIQ(srdb_node_prefix)
+PREDECL_RBTREE_UNIQ(srdb_area_prefix)
+PREDECL_RBTREE_UNIQ(srdb_prefix_cfg)
+
+/* Segment Routing Adjacency-SID type. */
+enum sr_adj_type {
+ ISIS_SR_ADJ_NORMAL = 0,
+ ISIS_SR_LAN_BACKUP,
+};
+
+/* Segment Routing Adjacency. */
+struct sr_adjacency {
+ /* Adjacency type. */
+ enum sr_adj_type type;
+
+ /* Adjacency-SID nexthop information. */
+ struct {
+ int family;
+ union g_addr address;
+ mpls_label_t label;
+ } nexthop;
+
+ /* (LAN-)Adjacency-SID Sub-TLV. */
+ union {
+ struct isis_adj_sid *adj_sid;
+ struct isis_lan_adj_sid *ladj_sid;
+ } u;
+
+ /* Back pointer to IS-IS adjacency. */
+ struct isis_adjacency *adj;
+};
+
+/* Segment Routing Prefix-SID type. */
+enum sr_prefix_type {
+ ISIS_SR_PREFIX_LOCAL = 0,
+ ISIS_SR_PREFIX_REMOTE,
+};
+
+/* Segment Routing Nexthop Information. */
+struct sr_nexthop_info {
+ mpls_label_t label;
+ time_t uptime;
+};
+
+/* State of Object (SR-Node and SR-Prefix) stored in SRDB */
+enum srdb_state {
+ SRDB_STATE_VALIDATED = 0,
+ SRDB_STATE_NEW,
+ SRDB_STATE_MODIFIED,
+ SRDB_STATE_UNCHANGED
+};
+
+/* Segment Routing Prefix-SID. */
+struct sr_prefix {
+ /* SRDB RB-tree entries. */
+ struct srdb_node_prefix_item node_entry;
+ struct srdb_area_prefix_item area_entry;
+
+ /* IP prefix. */
+ struct prefix prefix;
+
+ /* SID value, algorithm and flags subTLVs. */
+ struct isis_prefix_sid sid;
+
+ /* Input label value. */
+ mpls_label_t input_label;
+
+ /* Prefix-SID type. */
+ enum sr_prefix_type type;
+ union {
+ struct {
+ /* Information about this local Prefix-SID. */
+ struct sr_nexthop_info info;
+ } local;
+ struct {
+ /* Route associated to this remote Prefix-SID. */
+ struct isis_route_info *rinfo;
+ } remote;
+ } u;
+
+ /* Backpointer to Segment Routing node. */
+ struct sr_node *srn;
+
+ /* SR-Prefix State used while the LSPDB is being parsed. */
+ enum srdb_state state;
+};
+
+/* Segment Routing node. */
+struct sr_node {
+ /* SRDB RB-tree entry. */
+ struct srdb_node_item entry;
+
+ /* IS-IS level: ISIS_LEVEL1 or ISIS_LEVEL2. */
+ int level;
+
+ /* IS-IS node identifier. */
+ uint8_t sysid[ISIS_SYS_ID_LEN];
+
+ /* Segment Routing node capabilities (SRGB, SR Algorithms) subTLVs. */
+ struct isis_router_cap cap;
+
+ /* List of Prefix-SIDs advertised by this node. */
+ struct srdb_node_prefix_head prefix_sids;
+
+ /* Backpointer to IS-IS area. */
+ struct isis_area *area;
+
+ /* SR-Node State used while the LSPDB is being parsed. */
+ enum srdb_state state;
+};
+
+/* SID type. NOTE: these values must be in sync with the YANG module. */
+enum sr_sid_value_type {
+ SR_SID_VALUE_TYPE_INDEX = 0,
+ SR_SID_VALUE_TYPE_ABSOLUTE = 1,
+};
+
+#define IS_SID_VALUE(flag) CHECK_FLAG(flag, ISIS_PREFIX_SID_VALUE)
+
+/* Last Hop Behavior. NOTE: these values must be in sync with the YANG module */
+enum sr_last_hop_behavior {
+ SR_LAST_HOP_BEHAVIOR_EXP_NULL = 0,
+ SR_LAST_HOP_BEHAVIOR_NO_PHP = 1,
+ SR_LAST_HOP_BEHAVIOR_PHP = 2,
+};
+
+/* Segment Routing Prefix-SID configuration. */
+struct sr_prefix_cfg {
+ /* SRDB RB-tree entry. */
+ struct srdb_prefix_cfg_item entry;
+
+ /* IP prefix. */
+ struct prefix prefix;
+
+ /* SID value. */
+ uint32_t sid;
+
+ /* SID value type. */
+ enum sr_sid_value_type sid_type;
+
+ /* SID last hop behavior. */
+ enum sr_last_hop_behavior last_hop_behavior;
+
+ /* Does this Prefix-SID refer to a loopback address (Node-SID)? */
+ bool node_sid;
+
+ /* Backpointer to IS-IS area. */
+ struct isis_area *area;
+};
+
+/* Per-area IS-IS Segment Routing Data Base (SRDB). */
+struct isis_sr_db {
+ /* Global Operational status of Segment Routing. */
+ bool enabled;
+
+ /* List of local Adjacency-SIDs. */
+ struct list *adj_sids;
+
+ /* Segment Routing Node information per IS-IS level. */
+ struct srdb_node_head sr_nodes[ISIS_LEVELS];
+
+ /* Segment Routing Prefix-SIDs per IS-IS level. */
+ struct srdb_area_prefix_head prefix_sids[ISIS_LEVELS];
+
+ /* Area Segment Routing configuration. */
+ struct {
+ /* Administrative status of Segment Routing. */
+ bool enabled;
+
+ /* Segment Routing Global Block lower & upper bound. */
+ uint32_t srgb_lower_bound;
+ uint32_t srgb_upper_bound;
+
+ /* Maximum SID Depth supported by the node. */
+ uint8_t msd;
+
+ /* Prefix-SID mappings. */
+ struct srdb_prefix_cfg_head prefix_sids;
+ } config;
+};
+
+/* Prototypes. */
+extern int isis_sr_cfg_srgb_update(struct isis_area *area, uint32_t lower_bound,
+ uint32_t upper_bound);
+extern struct sr_prefix_cfg *
+isis_sr_cfg_prefix_add(struct isis_area *area, const struct prefix *prefix);
+extern void isis_sr_cfg_prefix_del(struct sr_prefix_cfg *pcfg);
+extern struct sr_prefix_cfg *
+isis_sr_cfg_prefix_find(struct isis_area *area, union prefixconstptr prefix);
+extern void isis_sr_prefix_cfg2subtlv(const struct sr_prefix_cfg *pcfg,
+ bool external,
+ struct isis_prefix_sid *psid);
+extern void isis_sr_nexthop_update(struct sr_nexthop_info *srnh,
+ mpls_label_t label);
+extern void isis_sr_nexthop_reset(struct sr_nexthop_info *srnh);
+extern void isis_area_verify_sr(struct isis_area *area);
+extern int isis_sr_start(struct isis_area *area);
+extern void isis_sr_stop(struct isis_area *area);
+extern void isis_sr_area_init(struct isis_area *area);
+extern void isis_sr_area_term(struct isis_area *area);
+extern void isis_sr_init(void);
+extern void isis_sr_term(void);
+
+#endif /* _FRR_ISIS_SR_H */
diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c
index 5b0b709206..923956fa6d 100644
--- a/isisd/isis_tlvs.c
+++ b/isisd/isis_tlvs.c
@@ -43,9 +43,10 @@
#include "isisd/isis_pdu.h"
#include "isisd/isis_lsp.h"
#include "isisd/isis_te.h"
+#include "isisd/isis_sr.h"
DEFINE_MTYPE_STATIC(ISISD, ISIS_TLV, "ISIS TLVs")
-DEFINE_MTYPE_STATIC(ISISD, ISIS_SUBTLV, "ISIS Sub-TLVs")
+DEFINE_MTYPE(ISISD, ISIS_SUBTLV, "ISIS Sub-TLVs")
DEFINE_MTYPE_STATIC(ISISD, ISIS_MT_ITEM_LIST, "ISIS MT Item Lists")
typedef int (*unpack_tlv_func)(enum isis_tlv_context context, uint8_t tlv_type,
@@ -283,7 +284,7 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
sbuf_push(buf, indent,
"Unidir. Utilized Bandwidth: %g (Bytes/sec)\n",
exts->use_bw);
- /* Segment Routing Adjacency */
+ /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
if (IS_SUBTLV(exts, EXT_ADJ_SID)) {
struct isis_adj_sid *adj;
@@ -314,6 +315,7 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
: '0');
}
}
+ /* Segment Routing LAN-Adjacency as per RFC8667 section #2.2.2 */
if (IS_SUBTLV(exts, EXT_LAN_ADJ_SID)) {
struct isis_lan_adj_sid *lan;
@@ -475,6 +477,7 @@ static int pack_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
stream_putc(s, ISIS_SUBTLV_DEF_SIZE);
stream_putf(s, exts->use_bw);
}
+ /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
if (IS_SUBTLV(exts, EXT_ADJ_SID)) {
struct isis_adj_sid *adj;
@@ -494,6 +497,7 @@ static int pack_item_ext_subtlvs(struct isis_ext_subtlvs *exts,
}
}
+ /* Segment Routing LAN-Adjacency as per RFC8667 section #2.2.2 */
if (IS_SUBTLV(exts, EXT_LAN_ADJ_SID)) {
struct isis_lan_adj_sid *lan;
@@ -720,7 +724,7 @@ static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s,
SET_SUBTLV(exts, EXT_USE_BW);
}
break;
- /* Segment Routing Adjacency */
+ /* Segment Routing Adjacency as per RFC8667 section #2.2.1 */
case ISIS_SUBTLV_ADJ_SID:
if (subtlv_len != ISIS_SUBTLV_ADJ_SID_SIZE
&& subtlv_len != ISIS_SUBTLV_ADJ_SID_SIZE + 1) {
@@ -748,6 +752,7 @@ static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s,
SET_SUBTLV(exts, EXT_ADJ_SID);
}
break;
+ /* Segment Routing LAN-Adjacency as per RFC8667 section 2.2.2 */
case ISIS_SUBTLV_LAN_ADJ_SID:
if (subtlv_len != ISIS_SUBTLV_LAN_ADJ_SID_SIZE
&& subtlv_len != ISIS_SUBTLV_LAN_ADJ_SID_SIZE + 1) {
@@ -788,7 +793,7 @@ static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s,
return 0;
}
-/* Functions for Sub-TLV 3 SR Prefix-SID */
+/* Functions for Sub-TLV 3 SR Prefix-SID as per RFC8667 section 2.1 */
static struct isis_item *copy_item_prefix_sid(struct isis_item *i)
{
struct isis_prefix_sid *sid = (struct isis_prefix_sid *)i;
@@ -887,7 +892,11 @@ static int unpack_item_prefix_sid(uint16_t mtid, uint8_t len, struct stream *s,
if (sid.flags & ISIS_PREFIX_SID_VALUE) {
sid.value = stream_get3(s);
- sid.value &= MPLS_LABEL_VALUE_MASK;
+ if (!IS_MPLS_UNRESERVED_LABEL(sid.value)) {
+ sbuf_push(log, indent, "Invalid absolute SID %u\n",
+ sid.value);
+ return 1;
+ }
} else {
sid.value = stream_getl(s);
}
@@ -2580,7 +2589,7 @@ out:
return 1;
}
-/* Functions related to TLV 242 Router Capability */
+/* Functions related to TLV 242 Router Capability as per RFC7981 */
static struct isis_router_cap *copy_tlv_router_cap(
const struct isis_router_cap *router_cap)
{
@@ -2609,7 +2618,7 @@ static void format_tlv_router_cap(const struct isis_router_cap *router_cap,
router_cap->flags & ISIS_ROUTER_CAP_FLAG_D ? '1' : '0',
router_cap->flags & ISIS_ROUTER_CAP_FLAG_S ? '1' : '0');
- /* SR Global Block */
+ /* Segment Routing Global Block as per RFC8667 section #3.1 */
if (router_cap->srgb.range_size != 0)
sbuf_push(buf, indent,
" Segment Routing: I:%s V:%s, SRGB Base: %d Range: %d\n",
@@ -2618,12 +2627,12 @@ static void format_tlv_router_cap(const struct isis_router_cap *router_cap,
router_cap->srgb.lower_bound,
router_cap->srgb.range_size);
- /* SR Algorithms */
+ /* Segment Routing Algorithms as per RFC8667 section #3.2 */
if (router_cap->algo[0] != SR_ALGORITHM_UNSET) {
sbuf_push(buf, indent, " Algorithm: %s",
router_cap->algo[0] == 0 ? "0: SPF"
: "0: Strict SPF");
- for (int i = 0; i < SR_ALGORITHM_COUNT; i++)
+ for (int i = 1; i < SR_ALGORITHM_COUNT; i++)
if (router_cap->algo[i] != SR_ALGORITHM_UNSET)
sbuf_push(buf, indent, " %s",
router_cap->algo[1] == 0
@@ -2632,7 +2641,7 @@ static void format_tlv_router_cap(const struct isis_router_cap *router_cap,
sbuf_push(buf, indent, "\n");
}
- /* SR Node MSSD */
+ /* Segment Routing Node MSD as per RFC8491 section #2 */
if (router_cap->msd != 0)
sbuf_push(buf, indent, " Node MSD: %d\n", router_cap->msd);
}
@@ -2669,7 +2678,7 @@ static int pack_tlv_router_cap(const struct isis_router_cap *router_cap,
stream_put_ipv4(s, router_cap->router_id.s_addr);
stream_putc(s, router_cap->flags);
- /* Add SRGB if set */
+ /* Add SRGB if set as per RFC8667 section #3.1 */
if ((router_cap->srgb.range_size != 0)
&& (router_cap->srgb.lower_bound != 0)) {
stream_putc(s, ISIS_SUBTLV_SID_LABEL_RANGE);
@@ -2680,7 +2689,7 @@ static int pack_tlv_router_cap(const struct isis_router_cap *router_cap,
stream_putc(s, ISIS_SUBTLV_SID_LABEL_SIZE);
stream_put3(s, router_cap->srgb.lower_bound);
- /* Then SR Algorithm if set */
+ /* Then SR Algorithm if set as per RFC8667 section #3.2 */
for (nb_algo = 0; nb_algo < SR_ALGORITHM_COUNT; nb_algo++)
if (router_cap->algo[nb_algo] == SR_ALGORITHM_UNSET)
break;
@@ -2690,7 +2699,7 @@ static int pack_tlv_router_cap(const struct isis_router_cap *router_cap,
for (int i = 0; i < nb_algo; i++)
stream_putc(s, router_cap->algo[i]);
}
- /* And finish with MSD if set */
+ /* And finish with MSD if set as per RFC8491 section #2 */
if (router_cap->msd != 0) {
stream_putc(s, ISIS_SUBTLV_NODE_MSD);
stream_putc(s, ISIS_SUBTLV_NODE_MSD_SIZE);
@@ -4413,10 +4422,22 @@ static void tlvs_protocols_supported_to_adj(struct isis_tlvs *tlvs,
memcpy(adj->nlpids.nlpids, reduced.nlpids, reduced.count);
}
+DEFINE_HOOK(isis_adj_ip_enabled_hook, (struct isis_adjacency *adj, int family),
+ (adj, family))
+DEFINE_HOOK(isis_adj_ip_disabled_hook,
+ (struct isis_adjacency *adj, int family), (adj, family))
+
static void tlvs_ipv4_addresses_to_adj(struct isis_tlvs *tlvs,
struct isis_adjacency *adj,
bool *changed)
{
+ bool ipv4_enabled = false;
+
+ if (adj->ipv4_address_count == 0 && tlvs->ipv4_address.count > 0)
+ ipv4_enabled = true;
+ else if (adj->ipv4_address_count > 0 && tlvs->ipv4_address.count == 0)
+ hook_call(isis_adj_ip_disabled_hook, adj, AF_INET);
+
if (adj->ipv4_address_count != tlvs->ipv4_address.count) {
*changed = true;
adj->ipv4_address_count = tlvs->ipv4_address.count;
@@ -4440,12 +4461,22 @@ static void tlvs_ipv4_addresses_to_adj(struct isis_tlvs *tlvs,
*changed = true;
adj->ipv4_addresses[i] = addr->addr;
}
+
+ if (ipv4_enabled)
+ hook_call(isis_adj_ip_enabled_hook, adj, AF_INET);
}
static void tlvs_ipv6_addresses_to_adj(struct isis_tlvs *tlvs,
struct isis_adjacency *adj,
bool *changed)
{
+ bool ipv6_enabled = false;
+
+ if (adj->ipv6_address_count == 0 && tlvs->ipv6_address.count > 0)
+ ipv6_enabled = true;
+ else if (adj->ipv6_address_count > 0 && tlvs->ipv6_address.count == 0)
+ hook_call(isis_adj_ip_disabled_hook, adj, AF_INET6);
+
if (adj->ipv6_address_count != tlvs->ipv6_address.count) {
*changed = true;
adj->ipv6_address_count = tlvs->ipv6_address.count;
@@ -4469,6 +4500,9 @@ static void tlvs_ipv6_addresses_to_adj(struct isis_tlvs *tlvs,
*changed = true;
adj->ipv6_addresses[i] = addr->addr;
}
+
+ if (ipv6_enabled)
+ hook_call(isis_adj_ip_enabled_hook, adj, AF_INET6);
}
void isis_tlvs_to_adj(struct isis_tlvs *tlvs, struct isis_adjacency *adj,
@@ -4572,6 +4606,7 @@ void isis_tlvs_add_oldstyle_ip_reach(struct isis_tlvs *tlvs,
append_item(&tlvs->oldstyle_ip_reach, (struct isis_item *)r);
}
+/* Add IS-IS SR Adjacency-SID subTLVs */
void isis_tlvs_add_adj_sid(struct isis_ext_subtlvs *exts,
struct isis_adj_sid *adj)
{
@@ -4579,6 +4614,7 @@ void isis_tlvs_add_adj_sid(struct isis_ext_subtlvs *exts,
SET_SUBTLV(exts, EXT_ADJ_SID);
}
+/* Delete IS-IS SR Adjacency-SID subTLVs */
void isis_tlvs_del_adj_sid(struct isis_ext_subtlvs *exts,
struct isis_adj_sid *adj)
{
@@ -4588,6 +4624,7 @@ void isis_tlvs_del_adj_sid(struct isis_ext_subtlvs *exts,
UNSET_SUBTLV(exts, EXT_ADJ_SID);
}
+/* Add IS-IS SR LAN-Adjacency-SID subTLVs */
void isis_tlvs_add_lan_adj_sid(struct isis_ext_subtlvs *exts,
struct isis_lan_adj_sid *lan)
{
@@ -4595,6 +4632,7 @@ void isis_tlvs_add_lan_adj_sid(struct isis_ext_subtlvs *exts,
SET_SUBTLV(exts, EXT_LAN_ADJ_SID);
}
+/* Delete IS-IS SR LAN-Adjacency-SID subTLVs */
void isis_tlvs_del_lan_adj_sid(struct isis_ext_subtlvs *exts,
struct isis_lan_adj_sid *lan)
{
@@ -4605,24 +4643,42 @@ void isis_tlvs_del_lan_adj_sid(struct isis_ext_subtlvs *exts,
}
void isis_tlvs_add_extended_ip_reach(struct isis_tlvs *tlvs,
- struct prefix_ipv4 *dest, uint32_t metric)
+ struct prefix_ipv4 *dest, uint32_t metric,
+ bool external, struct sr_prefix_cfg *pcfg)
{
struct isis_extended_ip_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r));
r->metric = metric;
memcpy(&r->prefix, dest, sizeof(*dest));
apply_mask_ipv4(&r->prefix);
+ if (pcfg) {
+ struct isis_prefix_sid *psid =
+ XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*psid));
+
+ isis_sr_prefix_cfg2subtlv(pcfg, external, psid);
+ r->subtlvs = isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH);
+ append_item(&r->subtlvs->prefix_sids, (struct isis_item *)psid);
+ }
append_item(&tlvs->extended_ip_reach, (struct isis_item *)r);
}
void isis_tlvs_add_ipv6_reach(struct isis_tlvs *tlvs, uint16_t mtid,
- struct prefix_ipv6 *dest, uint32_t metric)
+ struct prefix_ipv6 *dest, uint32_t metric,
+ bool external, struct sr_prefix_cfg *pcfg)
{
struct isis_ipv6_reach *r = XCALLOC(MTYPE_ISIS_TLV, sizeof(*r));
r->metric = metric;
memcpy(&r->prefix, dest, sizeof(*dest));
apply_mask_ipv6(&r->prefix);
+ if (pcfg) {
+ struct isis_prefix_sid *psid =
+ XCALLOC(MTYPE_ISIS_SUBTLV, sizeof(*psid));
+
+ isis_sr_prefix_cfg2subtlv(pcfg, external, psid);
+ r->subtlvs = isis_alloc_subtlvs(ISIS_CONTEXT_SUBTLV_IP_REACH);
+ append_item(&r->subtlvs->prefix_sids, (struct isis_item *)psid);
+ }
struct isis_item_list *l;
l = (mtid == ISIS_MT_IPV4_UNICAST)
@@ -4636,7 +4692,7 @@ void isis_tlvs_add_ipv6_dstsrc_reach(struct isis_tlvs *tlvs, uint16_t mtid,
struct prefix_ipv6 *src,
uint32_t metric)
{
- isis_tlvs_add_ipv6_reach(tlvs, mtid, dest, metric);
+ isis_tlvs_add_ipv6_reach(tlvs, mtid, dest, metric, false, NULL);
struct isis_item_list *l = isis_get_mt_items(&tlvs->mt_ipv6_reach,
mtid);
diff --git a/isisd/isis_tlvs.h b/isisd/isis_tlvs.h
index 2948728e2b..f468d85bbd 100644
--- a/isisd/isis_tlvs.h
+++ b/isisd/isis_tlvs.h
@@ -28,8 +28,11 @@
#include "openbsd-tree.h"
#include "prefix.h"
+DECLARE_MTYPE(ISIS_SUBTLV)
+
struct lspdb_head;
struct isis_subtlvs;
+struct sr_prefix_cfg;
struct isis_area_address;
struct isis_area_address {
@@ -132,10 +135,7 @@ struct isis_threeway_adj {
uint32_t neighbor_circuit_id;
};
-/*
- * Segment Routing subTLV's as per
- * draft-ietf-isis-segment-routing-extension-25
- */
+/* Segment Routing subTLV's as per RFC8667 */
#define ISIS_SUBTLV_SRGB_FLAG_I 0x80
#define ISIS_SUBTLV_SRGB_FLAG_V 0x40
#define IS_SR_IPV4(srgb) (srgb.flags & ISIS_SUBTLV_SRGB_FLAG_I)
@@ -213,7 +213,7 @@ struct isis_router_cap {
struct in_addr router_id;
uint8_t flags;
- /* draft-ietf-segment-routing-extensions-25 */
+ /* RFC 8667 section #3 */
struct isis_srgb srgb;
uint8_t algo[SR_ALGORITHM_COUNT];
/* RFC 8491 */
@@ -341,7 +341,7 @@ struct isis_subtlvs {
/* draft-baker-ipv6-isis-dst-src-routing-06 */
struct prefix_ipv6 *source_prefix;
- /* draft-ietf-isis-segment-routing-extensions-25 */
+ /* RFC 8667 section #2.4 */
struct isis_item_list prefix_sids;
};
@@ -391,15 +391,17 @@ enum isis_tlv_type {
/* RFC 5307 */
ISIS_SUBTLV_LLRI = 4,
+ /* RFC 8491 */
+ ISIS_SUBTLV_NODE_MSD = 23,
+
/* RFC 5316 */
ISIS_SUBTLV_RAS = 24,
ISIS_SUBTLV_RIP = 25,
- /* draft-isis-segment-routing-extension-25 */
+ /* RFC 8667 section #2 */
ISIS_SUBTLV_SID_LABEL = 1,
ISIS_SUBTLV_SID_LABEL_RANGE = 2,
ISIS_SUBTLV_ALGORITHM = 19,
- ISIS_SUBTLV_NODE_MSD = 23,
ISIS_SUBTLV_PREFIX_SID = 3,
ISIS_SUBTLV_ADJ_SID = 31,
ISIS_SUBTLV_LAN_ADJ_SID = 32,
@@ -418,21 +420,26 @@ enum isis_tlv_type {
/* subTLVs size for TE and SR */
enum ext_subtlv_size {
+ /* RFC 5307 */
ISIS_SUBTLV_LLRI_SIZE = 8,
+ /* RFC 5305 & RFC 6119 */
ISIS_SUBTLV_UNRSV_BW_SIZE = 32,
ISIS_SUBTLV_TE_METRIC_SIZE = 3,
ISIS_SUBTLV_IPV6_ADDR_SIZE = 16,
- /* draft-isis-segment-routing-extension-25 */
+ /* RFC 8491 */
+ ISIS_SUBTLV_NODE_MSD_SIZE = 2,
+
+ /* RFC 8667 section #2 */
ISIS_SUBTLV_SID_LABEL_SIZE = 3,
ISIS_SUBTLV_SID_LABEL_RANGE_SIZE = 9,
ISIS_SUBTLV_ALGORITHM_SIZE = 4,
- ISIS_SUBTLV_NODE_MSD_SIZE = 2,
ISIS_SUBTLV_ADJ_SID_SIZE = 5,
ISIS_SUBTLV_LAN_ADJ_SID_SIZE = 11,
ISIS_SUBTLV_PREFIX_SID_SIZE = 5,
+ /* RFC 7810 */
ISIS_SUBTLV_MM_DELAY_SIZE = 8,
ISIS_SUBTLV_HDR_SIZE = 2,
@@ -580,9 +587,11 @@ void isis_tlvs_set_te_router_id(struct isis_tlvs *tlvs,
void isis_tlvs_add_oldstyle_ip_reach(struct isis_tlvs *tlvs,
struct prefix_ipv4 *dest, uint8_t metric);
void isis_tlvs_add_extended_ip_reach(struct isis_tlvs *tlvs,
- struct prefix_ipv4 *dest, uint32_t metric);
+ struct prefix_ipv4 *dest, uint32_t metric,
+ bool external, struct sr_prefix_cfg *pcfg);
void isis_tlvs_add_ipv6_reach(struct isis_tlvs *tlvs, uint16_t mtid,
- struct prefix_ipv6 *dest, uint32_t metric);
+ struct prefix_ipv6 *dest, uint32_t metric,
+ bool external, struct sr_prefix_cfg *pcfg);
void isis_tlvs_add_ipv6_dstsrc_reach(struct isis_tlvs *tlvs, uint16_t mtid,
struct prefix_ipv6 *dest,
struct prefix_ipv6 *src,
diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c
index 630264768f..e0bf0cee14 100644
--- a/isisd/isis_zebra.c
+++ b/isisd/isis_zebra.c
@@ -49,9 +49,18 @@
#include "isisd/isis_lsp.h"
#include "isisd/isis_route.h"
#include "isisd/isis_zebra.h"
+#include "isisd/isis_adjacency.h"
#include "isisd/isis_te.h"
+#include "isisd/isis_sr.h"
-struct zclient *zclient = NULL;
+struct zclient *zclient;
+static struct zclient *zclient_sync;
+
+/* List of chunks of labels externally assigned by zebra. */
+static struct list *label_chunk_list;
+static struct listnode *current_label_chunk;
+
+static void isis_zebra_label_manager_connect(void);
/* Router-id update message from zebra. */
static int isis_router_id_update_zebra(ZAPI_CALLBACK_ARGS)
@@ -245,6 +254,160 @@ void isis_zebra_route_del_route(struct prefix *prefix,
zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api);
}
+/**
+ * Install Prefix-SID in the forwarding plane through Zebra.
+ *
+ * @param srp Segment Routing Prefix-SID
+ */
+static void isis_zebra_prefix_install_prefix_sid(const struct sr_prefix *srp)
+{
+ struct zapi_labels zl;
+ struct zapi_nexthop *znh;
+ struct listnode *node;
+ struct isis_nexthop *nexthop;
+ struct interface *ifp;
+
+ /* Prepare message. */
+ memset(&zl, 0, sizeof(zl));
+ zl.type = ZEBRA_LSP_ISIS_SR;
+ zl.local_label = srp->input_label;
+
+ switch (srp->type) {
+ case ISIS_SR_PREFIX_LOCAL:
+ ifp = if_lookup_by_name("lo", VRF_DEFAULT);
+ if (!ifp) {
+ zlog_warn(
+ "%s: couldn't install Prefix-SID %pFX: loopback interface not found",
+ __func__, &srp->prefix);
+ return;
+ }
+
+ znh = &zl.nexthops[zl.nexthop_num++];
+ znh->type = NEXTHOP_TYPE_IFINDEX;
+ znh->ifindex = ifp->ifindex;
+ znh->label_num = 1;
+ znh->labels[0] = MPLS_LABEL_IMPLICIT_NULL;
+ break;
+ case ISIS_SR_PREFIX_REMOTE:
+ /* Update route in the RIB too. */
+ SET_FLAG(zl.message, ZAPI_LABELS_FTN);
+ zl.route.prefix = srp->prefix;
+ zl.route.type = ZEBRA_ROUTE_ISIS;
+ zl.route.instance = 0;
+
+ for (ALL_LIST_ELEMENTS_RO(srp->u.remote.rinfo->nexthops, node,
+ nexthop)) {
+ if (nexthop->sr.label == MPLS_INVALID_LABEL)
+ continue;
+
+ if (zl.nexthop_num >= MULTIPATH_NUM)
+ break;
+
+ znh = &zl.nexthops[zl.nexthop_num++];
+ znh->type = (srp->prefix.family == AF_INET)
+ ? NEXTHOP_TYPE_IPV4_IFINDEX
+ : NEXTHOP_TYPE_IPV6_IFINDEX;
+ znh->gate = nexthop->ip;
+ znh->ifindex = nexthop->ifindex;
+ znh->label_num = 1;
+ znh->labels[0] = nexthop->sr.label;
+ }
+ break;
+ }
+
+ /* Send message to zebra. */
+ (void)zebra_send_mpls_labels(zclient, ZEBRA_MPLS_LABELS_REPLACE, &zl);
+}
+
+/**
+ * Uninstall Prefix-SID from the forwarding plane through Zebra.
+ *
+ * @param srp Segment Routing Prefix-SID
+ */
+static void isis_zebra_uninstall_prefix_sid(const struct sr_prefix *srp)
+{
+ struct zapi_labels zl;
+
+ /* Prepare message. */
+ memset(&zl, 0, sizeof(zl));
+ zl.type = ZEBRA_LSP_ISIS_SR;
+ zl.local_label = srp->input_label;
+
+ if (srp->type == ISIS_SR_PREFIX_REMOTE) {
+ /* Update route in the RIB too. */
+ SET_FLAG(zl.message, ZAPI_LABELS_FTN);
+ zl.route.prefix = srp->prefix;
+ zl.route.type = ZEBRA_ROUTE_ISIS;
+ zl.route.instance = 0;
+ }
+
+ /* Send message to zebra. */
+ (void)zebra_send_mpls_labels(zclient, ZEBRA_MPLS_LABELS_DELETE, &zl);
+}
+
+/**
+ * Send Prefix-SID to ZEBRA for installation or deletion.
+ *
+ * @param cmd ZEBRA_MPLS_LABELS_REPLACE or ZEBRA_ROUTE_DELETE
+ * @param srp Segment Routing Prefix-SID
+ */
+void isis_zebra_send_prefix_sid(int cmd, const struct sr_prefix *srp)
+{
+
+ if (cmd != ZEBRA_MPLS_LABELS_REPLACE
+ && cmd != ZEBRA_MPLS_LABELS_DELETE) {
+ flog_warn(EC_LIB_DEVELOPMENT, "%s: wrong ZEBRA command",
+ __func__);
+ return;
+ }
+
+ sr_debug(" |- %s label %u for prefix %pFX",
+ cmd == ZEBRA_MPLS_LABELS_REPLACE ? "Update" : "Delete",
+ srp->input_label, &srp->prefix);
+
+ if (cmd == ZEBRA_MPLS_LABELS_REPLACE)
+ isis_zebra_prefix_install_prefix_sid(srp);
+ else
+ isis_zebra_uninstall_prefix_sid(srp);
+}
+
+/**
+ * Send (LAN)-Adjacency-SID to ZEBRA for installation or deletion.
+ *
+ * @param cmd ZEBRA_MPLS_LABELS_ADD or ZEBRA_ROUTE_DELETE
+ * @param sra Segment Routing Adjacency-SID
+ */
+void isis_zebra_send_adjacency_sid(int cmd, const struct sr_adjacency *sra)
+{
+ struct zapi_labels zl;
+ struct zapi_nexthop *znh;
+
+ if (cmd != ZEBRA_MPLS_LABELS_ADD && cmd != ZEBRA_MPLS_LABELS_DELETE) {
+ flog_warn(EC_LIB_DEVELOPMENT, "%s: wrong ZEBRA command",
+ __func__);
+ return;
+ }
+
+ sr_debug(" |- %s label %u for interface %s",
+ cmd == ZEBRA_MPLS_LABELS_ADD ? "Add" : "Delete",
+ sra->nexthop.label, sra->adj->circuit->interface->name);
+
+ memset(&zl, 0, sizeof(zl));
+ zl.type = ZEBRA_LSP_ISIS_SR;
+ zl.local_label = sra->nexthop.label;
+ zl.nexthop_num = 1;
+ znh = &zl.nexthops[0];
+ znh->gate = sra->nexthop.address;
+ znh->type = (sra->nexthop.family == AF_INET)
+ ? NEXTHOP_TYPE_IPV4_IFINDEX
+ : NEXTHOP_TYPE_IPV6_IFINDEX;
+ znh->ifindex = sra->adj->circuit->interface->ifindex;
+ znh->label_num = 1;
+ znh->labels[0] = MPLS_LABEL_IMPLICIT_NULL;
+
+ (void)zebra_send_mpls_labels(zclient, cmd, &zl);
+}
+
static int isis_zebra_read(ZAPI_CALLBACK_ARGS)
{
struct zapi_route api;
@@ -302,13 +465,250 @@ void isis_zebra_redistribute_unset(afi_t afi, int type)
type, 0, VRF_DEFAULT);
}
+/* Label Manager Functions */
+
+/**
+ * Request Label Range to the Label Manager.
+ *
+ * @param base base label of the label range to request
+ * @param chunk_size size of the label range to request
+ *
+ * @return 0 on success, -1 on failure
+ */
+int isis_zebra_request_label_range(uint32_t base, uint32_t chunk_size)
+{
+ int ret;
+ uint32_t start, end;
+
+ if (zclient_sync->sock == -1)
+ isis_zebra_label_manager_connect();
+
+ ret = lm_get_label_chunk(zclient_sync, 0, base, chunk_size, &start,
+ &end);
+ if (ret < 0) {
+ zlog_warn("%s: error getting label range!", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * Release Label Range to the Label Manager.
+ *
+ * @param start start of label range to release
+ * @param end end of label range to release
+ */
+void isis_zebra_release_label_range(uint32_t start, uint32_t end)
+{
+ int ret;
+
+ if (zclient_sync->sock == -1)
+ isis_zebra_label_manager_connect();
+
+ ret = lm_release_label_chunk(zclient_sync, start, end);
+ if (ret < 0)
+ zlog_warn("%s: error releasing label range!", __func__);
+}
+
+/**
+ * Get a new Label Chunk from the Label Manager. The new Label Chunk is
+ * added to the Label Chunk list.
+ *
+ * @return 0 on success, -1 on failure
+ */
+static int isis_zebra_get_label_chunk(void)
+{
+ int ret;
+ uint32_t start, end;
+ struct label_chunk *new_label_chunk;
+
+ if (zclient_sync->sock == -1)
+ isis_zebra_label_manager_connect();
+
+ ret = lm_get_label_chunk(zclient_sync, 0, MPLS_LABEL_BASE_ANY,
+ CHUNK_SIZE, &start, &end);
+ if (ret < 0) {
+ zlog_warn("%s: error getting label chunk!", __func__);
+ return -1;
+ }
+
+ new_label_chunk = calloc(1, sizeof(struct label_chunk));
+ if (!new_label_chunk) {
+ zlog_warn("%s: error trying to allocate label chunk %u - %u",
+ __func__, start, end);
+ return -1;
+ }
+
+ new_label_chunk->start = start;
+ new_label_chunk->end = end;
+ new_label_chunk->used_mask = 0;
+
+ listnode_add(label_chunk_list, (void *)new_label_chunk);
+
+ /* let's update current if needed */
+ if (!current_label_chunk)
+ current_label_chunk = listtail(label_chunk_list);
+
+ return 0;
+}
+
+/**
+ * Request a label from the Label Chunk list.
+ *
+ * @return valid label on success or MPLS_INVALID_LABEL on failure
+ */
+mpls_label_t isis_zebra_request_dynamic_label(void)
+{
+ struct label_chunk *label_chunk;
+ uint32_t i, size;
+ uint64_t pos;
+ uint32_t label = MPLS_INVALID_LABEL;
+
+ while (current_label_chunk) {
+ label_chunk = listgetdata(current_label_chunk);
+ if (!label_chunk)
+ goto end;
+
+ /* try to get next free label in currently used label chunk */
+ size = label_chunk->end - label_chunk->start + 1;
+ for (i = 0, pos = 1; i < size; i++, pos <<= 1) {
+ if (!(pos & label_chunk->used_mask)) {
+ label_chunk->used_mask |= pos;
+ label = label_chunk->start + i;
+ goto end;
+ }
+ }
+ current_label_chunk = listnextnode(current_label_chunk);
+ }
+
+end:
+ /*
+ * we moved till the last chunk, or were not able to find a label, so
+ * let's ask for another one.
+ */
+ if (!current_label_chunk
+ || current_label_chunk == listtail(label_chunk_list)
+ || label == MPLS_INVALID_LABEL) {
+ if (isis_zebra_get_label_chunk() != 0)
+ zlog_warn("%s: error getting label chunk!", __func__);
+ }
+
+ return label;
+}
+
+/**
+ * Delete a Label Chunk.
+ *
+ * @param val Pointer to the Label Chunk to free
+ */
+static void isis_zebra_del_label_chunk(void *val)
+{
+ free(val);
+}
+
+/**
+ * Release a pre-allocated Label chunk to the Label Manager.
+ *
+ * @param start start of the label chunk to release
+ * @param end end of the label chunk to release
+ *
+ * @return 0 on success, -1 on failure
+ */
+static int isis_zebra_release_label_chunk(uint32_t start, uint32_t end)
+{
+ int ret;
+
+ ret = lm_release_label_chunk(zclient_sync, start, end);
+ if (ret < 0) {
+ zlog_warn("%s: error releasing label chunk!", __func__);
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
+ * Release a pre-attributes label to the Label Chunk list.
+ *
+ * @param label Label to be release
+ */
+void isis_zebra_release_dynamic_label(mpls_label_t label)
+{
+ struct listnode *node;
+ struct label_chunk *label_chunk;
+ uint64_t pos;
+
+ for (ALL_LIST_ELEMENTS_RO(label_chunk_list, node, label_chunk)) {
+ if (!(label <= label_chunk->end && label >= label_chunk->start))
+ continue;
+
+ pos = 1ULL << (label - label_chunk->start);
+ label_chunk->used_mask &= ~pos;
+
+ /*
+ * If nobody is using this chunk and it's not
+ * current_label_chunk, then free it.
+ */
+ if (!label_chunk->used_mask && (current_label_chunk != node)) {
+ if (isis_zebra_release_label_chunk(label_chunk->start,
+ label_chunk->end)
+ != 0)
+ zlog_warn("%s: error releasing label chunk!",
+ __func__);
+ else {
+ listnode_delete(label_chunk_list, label_chunk);
+ isis_zebra_del_label_chunk(label_chunk);
+ }
+ }
+ break;
+ }
+}
+
+/**
+ * Connect to the Label Manager.
+ */
+static void isis_zebra_label_manager_connect(void)
+{
+ /* Connect to label manager. */
+ while (zclient_socket_connect(zclient_sync) < 0) {
+ zlog_warn("%s: re-attempt connecting synchronous zclient!",
+ __func__);
+ sleep(1);
+ }
+ /* make socket non-blocking */
+ set_nonblocking(zclient_sync->sock);
+
+ /* Send hello to notify zebra this is a synchronous client */
+ while (zclient_send_hello(zclient_sync) < 0) {
+ zlog_warn(
+ "%s: re-attempt sending hello for synchronous zclient!",
+ __func__);
+ sleep(1);
+ }
+
+ /* Connect to label manager */
+ while (lm_label_manager_connect(zclient_sync, 0) != 0) {
+ zlog_warn("%s: re-attempt connecting to label manager!", __func__);
+ sleep(1);
+ }
+
+ label_chunk_list = list_new();
+ label_chunk_list->del = isis_zebra_del_label_chunk;
+ while (isis_zebra_get_label_chunk() != 0) {
+ zlog_warn("%s: re-attempt getting first label chunk!", __func__);
+ sleep(1);
+ }
+}
+
static void isis_zebra_connected(struct zclient *zclient)
{
zclient_send_reg_requests(zclient, VRF_DEFAULT);
}
-void isis_zebra_init(struct thread_master *master)
+void isis_zebra_init(struct thread_master *master, int instance)
{
+ /* Initialize asynchronous zclient. */
zclient = zclient_new(master, &zclient_options_default);
zclient_init(zclient, PROTO_TYPE, 0, &isisd_privs);
zclient->zebra_connected = isis_zebra_connected;
@@ -319,7 +719,19 @@ void isis_zebra_init(struct thread_master *master)
zclient->redistribute_route_add = isis_zebra_read;
zclient->redistribute_route_del = isis_zebra_read;
- return;
+ /* Initialize special zclient for synchronous message exchanges. */
+ struct zclient_options options = zclient_options_default;
+ options.synchronous = true;
+ zclient_sync = zclient_new(master, &options);
+ zclient_sync->sock = -1;
+ zclient_sync->redist_default = ZEBRA_ROUTE_ISIS;
+ zclient_sync->instance = instance;
+ /*
+ * session_id must be different from default value (0) to distinguish
+ * the asynchronous socket from the synchronous one
+ */
+ zclient_sync->session_id = 1;
+ zclient_sync->privs = &isisd_privs;
}
void isis_zebra_stop(void)
diff --git a/isisd/isis_zebra.h b/isisd/isis_zebra.h
index d00f348c8e..b143d34626 100644
--- a/isisd/isis_zebra.h
+++ b/isisd/isis_zebra.h
@@ -24,10 +24,19 @@
extern struct zclient *zclient;
-void isis_zebra_init(struct thread_master *);
+struct label_chunk {
+ uint32_t start;
+ uint32_t end;
+ uint64_t used_mask;
+};
+#define CHUNK_SIZE 64
+
+void isis_zebra_init(struct thread_master *master, int instance);
void isis_zebra_stop(void);
struct isis_route_info;
+struct sr_prefix;
+struct sr_adjacency;
void isis_zebra_route_add_route(struct prefix *prefix,
struct prefix_ipv6 *src_p,
@@ -35,8 +44,14 @@ void isis_zebra_route_add_route(struct prefix *prefix,
void isis_zebra_route_del_route(struct prefix *prefix,
struct prefix_ipv6 *src_p,
struct isis_route_info *route_info);
+void isis_zebra_send_prefix_sid(int cmd, const struct sr_prefix *srp);
+void isis_zebra_send_adjacency_sid(int cmd, const struct sr_adjacency *sra);
int isis_distribute_list_update(int routetype);
void isis_zebra_redistribute_set(afi_t afi, int type);
void isis_zebra_redistribute_unset(afi_t afi, int type);
+int isis_zebra_request_label_range(uint32_t base, uint32_t chunk_size);
+void isis_zebra_release_label_range(uint32_t start, uint32_t end);
+mpls_label_t isis_zebra_request_dynamic_label(void);
+void isis_zebra_release_dynamic_label(mpls_label_t label);
#endif /* _ZEBRA_ISIS_ZEBRA_H */
diff --git a/isisd/isisd.c b/isisd/isisd.c
index 298629e246..caf50addd4 100644
--- a/isisd/isisd.c
+++ b/isisd/isisd.c
@@ -56,6 +56,7 @@
#include "isisd/isis_events.h"
#include "isisd/isis_te.h"
#include "isisd/isis_mt.h"
+#include "isisd/isis_sr.h"
#include "isisd/fabricd.h"
#include "isisd/isis_nb.h"
@@ -88,7 +89,6 @@ void isis_new(unsigned long process_id, vrf_id_t vrf_id)
isis->area_list = list_new();
isis->init_circ_list = list_new();
isis->uptime = time(NULL);
- isis->nexthops = list_new();
dyn_cache_init();
/*
* uncomment the next line for full debugs
@@ -129,6 +129,8 @@ struct isis_area *isis_area_create(const char *area_tag)
thread_add_timer(master, lsp_tick, area, 1, &area->t_tick);
flags_initialize(&area->flags);
+ isis_sr_area_init(area);
+
/*
* Default values
*/
@@ -272,6 +274,8 @@ int isis_area_destroy(const char *area_tag)
isis_area_invalidate_routes(area, area->is_type);
isis_area_verify_routes(area);
+ isis_sr_area_term(area);
+
spftree_area_del(area);
THREAD_TIMER_OFF(area->spf_timer[0]);
@@ -749,6 +753,9 @@ void print_debug(struct vty *vty, int flags, int onoff)
onoffs);
if (flags & DEBUG_SPF_EVENTS)
vty_out(vty, "IS-IS SPF events debugging is %s\n", onoffs);
+ if (flags & DEBUG_SR)
+ vty_out(vty, "IS-IS Segment Routing events debugging is %s\n",
+ onoffs);
if (flags & DEBUG_UPDATE_PACKETS)
vty_out(vty, "IS-IS Update related packet debugging is %s\n",
onoffs);
@@ -813,6 +820,10 @@ static int config_write_debug(struct vty *vty)
vty_out(vty, "debug " PROTO_NAME " spf-events\n");
write++;
}
+ if (flags & DEBUG_SR) {
+ vty_out(vty, "debug " PROTO_NAME " sr-events\n");
+ write++;
+ }
if (flags & DEBUG_UPDATE_PACKETS) {
vty_out(vty, "debug " PROTO_NAME " update-packets\n");
write++;
@@ -1012,6 +1023,33 @@ DEFUN (no_debug_isis_spfevents,
return CMD_SUCCESS;
}
+DEFUN (debug_isis_srevents,
+ debug_isis_srevents_cmd,
+ "debug " PROTO_NAME " sr-events",
+ DEBUG_STR
+ PROTO_HELP
+ "IS-IS Segment Routing Events\n")
+{
+ isis->debugs |= DEBUG_SR;
+ print_debug(vty, DEBUG_SR, 1);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN (no_debug_isis_srevents,
+ no_debug_isis_srevents_cmd,
+ "no debug " PROTO_NAME " sr-events",
+ NO_STR
+ UNDEBUG_STR
+ PROTO_HELP
+ "IS-IS Segment Routing Events\n")
+{
+ isis->debugs &= ~DEBUG_SR;
+ print_debug(vty, DEBUG_SR, 0);
+
+ return CMD_SUCCESS;
+}
+
DEFUN (debug_isis_rtevents,
debug_isis_rtevents_cmd,
"debug " PROTO_NAME " route-events",
@@ -2199,6 +2237,8 @@ void isis_init(void)
install_element(ENABLE_NODE, &no_debug_isis_upd_cmd);
install_element(ENABLE_NODE, &debug_isis_spfevents_cmd);
install_element(ENABLE_NODE, &no_debug_isis_spfevents_cmd);
+ install_element(ENABLE_NODE, &debug_isis_srevents_cmd);
+ install_element(ENABLE_NODE, &no_debug_isis_srevents_cmd);
install_element(ENABLE_NODE, &debug_isis_rtevents_cmd);
install_element(ENABLE_NODE, &no_debug_isis_rtevents_cmd);
install_element(ENABLE_NODE, &debug_isis_events_cmd);
@@ -2224,6 +2264,8 @@ void isis_init(void)
install_element(CONFIG_NODE, &no_debug_isis_upd_cmd);
install_element(CONFIG_NODE, &debug_isis_spfevents_cmd);
install_element(CONFIG_NODE, &no_debug_isis_spfevents_cmd);
+ install_element(CONFIG_NODE, &debug_isis_srevents_cmd);
+ install_element(CONFIG_NODE, &no_debug_isis_srevents_cmd);
install_element(CONFIG_NODE, &debug_isis_rtevents_cmd);
install_element(CONFIG_NODE, &no_debug_isis_rtevents_cmd);
install_element(CONFIG_NODE, &debug_isis_events_cmd);
diff --git a/isisd/isisd.h b/isisd/isisd.h
index 052cc10928..439428d797 100644
--- a/isisd/isisd.h
+++ b/isisd/isisd.h
@@ -30,6 +30,7 @@
#include "isisd/isis_redist.h"
#include "isisd/isis_pdu_counter.h"
#include "isisd/isis_circuit.h"
+#include "isisd/isis_sr.h"
#include "isis_flags.h"
#include "isis_lsp.h"
#include "isis_memory.h"
@@ -69,7 +70,6 @@ struct isis {
uint32_t router_id; /* Router ID from zebra */
struct list *area_list; /* list of IS-IS areas */
struct list *init_circ_list;
- struct list *nexthops; /* IP next hops from this IS */
uint8_t max_area_addrs; /* maximumAreaAdresses */
struct area_addr *man_area_addrs; /* manualAreaAddresses */
uint32_t debugs; /* bitmap for debug */
@@ -166,6 +166,8 @@ struct isis_area {
struct list *mt_settings;
/* MPLS-TE settings */
struct mpls_te_area *mta;
+ /* Segment Routing information */
+ struct isis_sr_db srdb;
int ipv6_circuits;
bool purge_originator;
/* Counters */
@@ -219,6 +221,10 @@ int isis_area_passwd_cleartext_set(struct isis_area *area, int level,
int isis_area_passwd_hmac_md5_set(struct isis_area *area, int level,
const char *passwd, uint8_t snp_auth);
+/* YANG paths */
+#define ISIS_INSTANCE "/frr-isisd:isis/instance"
+#define ISIS_SR "/frr-isisd:isis/instance/segment-routing"
+
/* Master of threads. */
extern struct thread_master *master;
@@ -234,6 +240,7 @@ extern struct thread_master *master;
#define DEBUG_FLOODING (1<<9)
#define DEBUG_BFD (1<<10)
#define DEBUG_TX_QUEUE (1<<11)
+#define DEBUG_SR (1<<12)
#define lsp_debug(...) \
do { \
@@ -247,6 +254,12 @@ extern struct thread_master *master;
zlog_debug(__VA_ARGS__); \
} while (0)
+#define sr_debug(...) \
+ do { \
+ if (IS_DEBUG_ISIS(DEBUG_SR)) \
+ zlog_debug(__VA_ARGS__); \
+ } while (0)
+
#define DEBUG_TE DEBUG_LSP_GEN
#define IS_DEBUG_ISIS(x) (isis->debugs & x)
diff --git a/isisd/subdir.am b/isisd/subdir.am
index 94f9116d34..9e855ad8cf 100644
--- a/isisd/subdir.am
+++ b/isisd/subdir.am
@@ -11,6 +11,7 @@ vtysh_scan += \
isisd/isis_redist.c \
isisd/isis_spf.c \
isisd/isis_te.c \
+ isisd/isis_sr.c \
isisd/isis_vty_fabricd.c \
isisd/isisd.c \
# end
@@ -48,6 +49,7 @@ noinst_HEADERS += \
isisd/isis_routemap.h \
isisd/isis_spf.h \
isisd/isis_spf_private.h \
+ isisd/isis_sr.h \
isisd/isis_te.h \
isisd/isis_tlvs.h \
isisd/isis_tx_queue.h \
@@ -77,6 +79,7 @@ LIBISIS_SOURCES = \
isisd/isis_route.c \
isisd/isis_routemap.c \
isisd/isis_spf.c \
+ isisd/isis_sr.c \
isisd/isis_te.c \
isisd/isis_tlvs.c \
isisd/isis_tx_queue.c \
diff --git a/ldpd/l2vpn.c b/ldpd/l2vpn.c
index b234e3ebe3..4a944fa019 100644
--- a/ldpd/l2vpn.c
+++ b/ldpd/l2vpn.c
@@ -303,6 +303,7 @@ l2vpn_pw_ok(struct l2vpn_pw *pw, struct fec_nh *fnh)
if (fnh->remote_label == NO_LABEL) {
log_warnx("%s: pseudowire %s: no remote label", __func__,
pw->ifname);
+ pw->reason = F_PW_NO_REMOTE_LABEL;
return (0);
}
@@ -310,6 +311,7 @@ l2vpn_pw_ok(struct l2vpn_pw *pw, struct fec_nh *fnh)
if (pw->l2vpn->mtu != pw->remote_mtu) {
log_warnx("%s: pseudowire %s: MTU mismatch detected", __func__,
pw->ifname);
+ pw->reason = F_PW_MTU_MISMATCH;
return (0);
}
@@ -318,9 +320,11 @@ l2vpn_pw_ok(struct l2vpn_pw *pw, struct fec_nh *fnh)
pw->remote_status != PW_FORWARDING) {
log_warnx("%s: pseudowire %s: remote end is down", __func__,
pw->ifname);
+ pw->reason = F_PW_REMOTE_NOT_FWD;
return (0);
}
+ pw->reason = F_PW_NO_ERR;
return (1);
}
@@ -517,10 +521,13 @@ l2vpn_pw_status_update(struct zapi_pw_status *zpw)
return (1);
}
- if (zpw->status == PW_STATUS_UP)
+ if (zpw->status == PW_STATUS_UP) {
local_status = PW_FORWARDING;
- else
+ pw->reason = F_PW_NO_ERR;
+ } else {
local_status = PW_NOT_FORWARDING;
+ pw->reason = F_PW_LOCAL_NOT_FWD;
+ }
/* local status didn't change */
if (pw->local_status == local_status)
@@ -604,6 +611,7 @@ l2vpn_binding_ctl(pid_t pid)
pwctl.local_ifmtu = pw->l2vpn->mtu;
pwctl.local_cword = (pw->flags & F_PW_CWORD_CONF) ?
1 : 0;
+ pwctl.reason = pw->reason;
} else
pwctl.local_label = NO_LABEL;
diff --git a/ldpd/lde.c b/ldpd/lde.c
index 7d1df158a5..3220278960 100644
--- a/ldpd/lde.c
+++ b/ldpd/lde.c
@@ -751,7 +751,6 @@ lde_update_label(struct fec_node *fn)
return (MPLS_LABEL_IMPLICIT_NULL);
return MPLS_LABEL_IPV6_EXPLICIT_NULL;
default:
- fatalx("lde_update_label: unexpected fec type");
break;
}
}
@@ -1421,8 +1420,10 @@ lde_nbr_del(struct lde_nbr *ln)
if (f->u.pwid.lsr_id.s_addr != ln->id.s_addr)
continue;
pw = (struct l2vpn_pw *) fn->data;
- if (pw)
+ if (pw) {
+ pw->reason = F_PW_NO_REMOTE_LABEL;
l2vpn_pw_reset(pw);
+ }
break;
default:
break;
diff --git a/ldpd/ldp_vty_exec.c b/ldpd/ldp_vty_exec.c
index d317da7b20..d74017c7e2 100644
--- a/ldpd/ldp_vty_exec.c
+++ b/ldpd/ldp_vty_exec.c
@@ -1256,6 +1256,8 @@ show_l2vpn_binding_msg(struct vty *vty, struct imsg *imsg,
"GroupID: %u\n", "", pw->local_cword,
pw_type_name(pw->type),pw->local_gid);
vty_out (vty, "%-8sMTU: %u\n", "",pw->local_ifmtu);
+ vty_out (vty, "%-8sLast failure: %s\n", "",
+ pw_error_code(pw->reason));
} else
vty_out (vty," Local Label: unassigned\n");
@@ -1309,6 +1311,8 @@ show_l2vpn_binding_msg_json(struct imsg *imsg, struct show_params *params,
pw->local_gid);
json_object_int_add(json_pw, "localIfMtu",
pw->local_ifmtu);
+ json_object_string_add(json_pw, "lastFailureReason",
+ pw_error_code(pw->reason));
} else
json_object_string_add(json_pw, "localLabel",
"unassigned");
diff --git a/ldpd/ldpd.h b/ldpd/ldpd.h
index 606fb372bb..c1bcc56c44 100644
--- a/ldpd/ldpd.h
+++ b/ldpd/ldpd.h
@@ -422,6 +422,7 @@ struct l2vpn_pw {
uint32_t local_status;
uint32_t remote_status;
uint8_t flags;
+ uint8_t reason;
QOBJ_FIELDS
};
RB_HEAD(l2vpn_pw_head, l2vpn_pw);
@@ -433,6 +434,12 @@ DECLARE_QOBJ_TYPE(l2vpn_pw)
#define F_PW_CWORD 0x08 /* control word negotiated */
#define F_PW_STATIC_NBR_ADDR 0x10 /* static neighbor address configured */
+#define F_PW_NO_ERR 0x00 /* no error reported */
+#define F_PW_LOCAL_NOT_FWD 0x01 /* locally can't forward over PW */
+#define F_PW_REMOTE_NOT_FWD 0x02 /* remote end of PW reported fwd error*/
+#define F_PW_NO_REMOTE_LABEL 0x03 /* have not recvd label from peer */
+#define F_PW_MTU_MISMATCH 0x04 /* mtu mismatch between peers */
+
struct l2vpn {
RB_ENTRY(l2vpn) entry;
char name[L2VPN_NAME_LEN];
@@ -662,6 +669,7 @@ struct ctl_pw {
uint16_t remote_ifmtu;
uint8_t remote_cword;
uint32_t status;
+ uint8_t reason;
};
extern struct ldpd_conf *ldpd_conf, *vty_conf;
@@ -808,6 +816,7 @@ const char *if_type_name(enum iface_type);
const char *msg_name(uint16_t);
const char *status_code_name(uint32_t);
const char *pw_type_name(uint16_t);
+const char *pw_error_code(uint8_t);
/* quagga */
extern struct thread_master *master;
diff --git a/ldpd/logmsg.c b/ldpd/logmsg.c
index 2c9fbf0dae..6427d0e13b 100644
--- a/ldpd/logmsg.c
+++ b/ldpd/logmsg.c
@@ -485,3 +485,25 @@ pw_type_name(uint16_t pw_type)
return (buf);
}
}
+
+const char *
+pw_error_code(uint8_t status)
+{
+ static char buf[16];
+
+ switch (status) {
+ case F_PW_NO_ERR:
+ return ("No Error");
+ case F_PW_LOCAL_NOT_FWD:
+ return ("local not forwarding");
+ case F_PW_REMOTE_NOT_FWD:
+ return ("remote not forwarding");
+ case F_PW_NO_REMOTE_LABEL:
+ return ("no remote label");
+ case F_PW_MTU_MISMATCH:
+ return ("mtu mismatch between peers");
+ default:
+ snprintf(buf, sizeof(buf), "[%0x]", status);
+ return (buf);
+ }
+}
diff --git a/lib/command.c b/lib/command.c
index d8a2270bc5..c9715965aa 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -836,6 +836,9 @@ enum node_type node_parent(enum node_type node)
case BFD_PEER_NODE:
ret = BFD_NODE;
break;
+ case BFD_PROFILE_NODE:
+ ret = BFD_NODE;
+ break;
default:
ret = CONFIG_NODE;
break;
diff --git a/lib/command.h b/lib/command.h
index 725a201446..ed0ea18d6f 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -155,6 +155,7 @@ enum node_type {
BGP_FLOWSPECV6_NODE, /* BGP IPv6 FLOWSPEC Address-Family */
BFD_NODE, /* BFD protocol mode. */
BFD_PEER_NODE, /* BFD peer configuration mode. */
+ BFD_PROFILE_NODE, /* BFD profile configuration mode. */
OPENFABRIC_NODE, /* OpenFabric router configuration node */
VRRP_NODE, /* VRRP node */
BMP_NODE, /* BMP config under router bgp */
@@ -403,6 +404,8 @@ struct cmd_node {
#define WATCHFRR_STR "watchfrr information\n"
#define ZEBRA_STR "Zebra information\n"
#define FILTER_LOG_STR "Filter Logs\n"
+#define BFD_PROFILE_STR "BFD profile.\n"
+#define BFD_PROFILE_NAME_STR "BFD profile name.\n"
#define CMD_VNI_RANGE "(1-16777215)"
#define CONF_BACKUP_EXT ".sav"
diff --git a/lib/if.c b/lib/if.c
index ff95cd9043..9efd298a4f 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -217,14 +217,16 @@ struct interface *if_create_name(const char *name, vrf_id_t vrf_id)
return ifp;
}
-struct interface *if_create_ifindex(ifindex_t ifindex, vrf_id_t vrf_id)
+struct interface *if_create_ifindex(ifindex_t ifindex, vrf_id_t vrf_id,
+ char *optional_name)
{
struct interface *ifp;
ifp = if_new(vrf_id);
if_set_index(ifp, ifindex);
-
+ if (optional_name)
+ if_set_name(ifp, optional_name);
hook_call(if_add, ifp);
return ifp;
}
@@ -410,7 +412,7 @@ struct interface *if_lookup_by_index_all_vrf(ifindex_t ifindex)
}
/* Lookup interface by IP address. */
-struct interface *if_lookup_exact_address(void *src, int family,
+struct interface *if_lookup_exact_address(const void *src, int family,
vrf_id_t vrf_id)
{
struct vrf *vrf = vrf_lookup_by_id(vrf_id);
@@ -442,7 +444,7 @@ struct interface *if_lookup_exact_address(void *src, int family,
}
/* Lookup interface by IP address. */
-struct connected *if_lookup_address(void *matchaddr, int family,
+struct connected *if_lookup_address(const void *matchaddr, int family,
vrf_id_t vrf_id)
{
struct vrf *vrf = vrf_lookup_by_id(vrf_id);
@@ -479,7 +481,7 @@ struct connected *if_lookup_address(void *matchaddr, int family,
}
/* Lookup interface by prefix */
-struct interface *if_lookup_prefix(struct prefix *prefix, vrf_id_t vrf_id)
+struct interface *if_lookup_prefix(const struct prefix *prefix, vrf_id_t vrf_id)
{
struct vrf *vrf = vrf_lookup_by_id(vrf_id);
struct listnode *cnode;
@@ -554,7 +556,8 @@ struct interface *if_get_by_name(const char *name, vrf_id_t vrf_id)
return NULL;
}
-struct interface *if_get_by_ifindex(ifindex_t ifindex, vrf_id_t vrf_id)
+struct interface *if_get_by_ifindex(ifindex_t ifindex, vrf_id_t vrf_id,
+ char *optional_name)
{
struct interface *ifp;
@@ -564,7 +567,7 @@ struct interface *if_get_by_ifindex(ifindex_t ifindex, vrf_id_t vrf_id)
ifp = if_lookup_by_ifindex(ifindex, vrf_id);
if (ifp)
return ifp;
- return if_create_ifindex(ifindex, vrf_id);
+ return if_create_ifindex(ifindex, vrf_id, optional_name);
case VRF_BACKEND_VRF_LITE:
ifp = if_lookup_by_index_all_vrf(ifindex);
if (ifp) {
@@ -576,7 +579,7 @@ struct interface *if_get_by_ifindex(ifindex_t ifindex, vrf_id_t vrf_id)
if_update_to_new_vrf(ifp, vrf_id);
return ifp;
}
- return if_create_ifindex(ifindex, vrf_id);
+ return if_create_ifindex(ifindex, vrf_id, optional_name);
}
return NULL;
@@ -982,7 +985,8 @@ nbr_connected_log(struct nbr_connected *connected, char *str)
}
/* If two connected address has same prefix return 1. */
-static int connected_same_prefix(struct prefix *p1, struct prefix *p2)
+static int connected_same_prefix(const struct prefix *p1,
+ const struct prefix *p2)
{
if (p1->family == p2->family) {
if (p1->family == AF_INET
@@ -1010,7 +1014,7 @@ unsigned int connected_count_by_family(struct interface *ifp, int family)
}
struct connected *connected_lookup_prefix_exact(struct interface *ifp,
- struct prefix *p)
+ const struct prefix *p)
{
struct listnode *node;
struct listnode *next;
@@ -1049,7 +1053,7 @@ struct connected *connected_delete_by_prefix(struct interface *ifp,
/* Find the address on our side that will be used when packets
are sent to dst. */
struct connected *connected_lookup_prefix(struct interface *ifp,
- struct prefix *addr)
+ const struct prefix *addr)
{
struct listnode *cnode;
struct connected *c;
@@ -1273,7 +1277,7 @@ struct if_link_params *if_link_params_get(struct interface *ifp)
/* Compute default bandwidth based on interface */
iflp->default_bw =
((ifp->bandwidth ? ifp->bandwidth : DEFAULT_BANDWIDTH)
- * TE_KILO_BIT / TE_BYTE);
+ * TE_MEGA_BIT / TE_BYTE);
/* Set Max, Reservable and Unreserved Bandwidth */
iflp->max_bw = iflp->default_bw;
diff --git a/lib/if.h b/lib/if.h
index ac8d8e70ba..e74e366e74 100644
--- a/lib/if.h
+++ b/lib/if.h
@@ -143,7 +143,7 @@ struct if_stats {
#define TE_EXT_MASK 0x0FFFFFFF
#define TE_EXT_ANORMAL 0x80000000
#define LOSS_PRECISION 0.000003
-#define TE_KILO_BIT 1000
+#define TE_MEGA_BIT 1000000
#define TE_BYTE 8
#define DEFAULT_BANDWIDTH 10000
#define MAX_CLASS_TYPE 8
@@ -509,14 +509,15 @@ extern void if_update_to_new_vrf(struct interface *, vrf_id_t vrf_id);
extern struct interface *if_create_name(const char *name, vrf_id_t vrf_id);
/* Create new interface, adds to index list only */
-extern struct interface *if_create_ifindex(ifindex_t ifindex, vrf_id_t vrf_id);
+extern struct interface *if_create_ifindex(ifindex_t ifindex, vrf_id_t vrf_id,
+ char *name);
extern struct interface *if_lookup_by_index(ifindex_t, vrf_id_t vrf_id);
extern struct interface *if_lookup_by_index_all_vrf(ifindex_t);
-extern struct interface *if_lookup_exact_address(void *matchaddr, int family,
- vrf_id_t vrf_id);
-extern struct connected *if_lookup_address(void *matchaddr, int family,
+extern struct interface *if_lookup_exact_address(const void *matchaddr,
+ int family, vrf_id_t vrf_id);
+extern struct connected *if_lookup_address(const void *matchaddr, int family,
vrf_id_t vrf_id);
-extern struct interface *if_lookup_prefix(struct prefix *prefix,
+extern struct interface *if_lookup_prefix(const struct prefix *prefix,
vrf_id_t vrf_id);
size_t if_lookup_by_hwaddr(const uint8_t *hw_addr, size_t addrsz,
struct interface ***result, vrf_id_t vrf_id);
@@ -524,8 +525,8 @@ size_t if_lookup_by_hwaddr(const uint8_t *hw_addr, size_t addrsz,
extern struct interface *if_lookup_by_name_all_vrf(const char *ifname);
extern struct interface *if_lookup_by_name(const char *ifname, vrf_id_t vrf_id);
extern struct interface *if_get_by_name(const char *ifname, vrf_id_t vrf_id);
-extern struct interface *if_get_by_ifindex(ifindex_t ifindex, vrf_id_t vrf_id);
-
+extern struct interface *if_get_by_ifindex(ifindex_t ifindex, vrf_id_t vrf_id,
+ char *optional_name);
/* Sets the index and adds to index list */
extern int if_set_index(struct interface *ifp, ifindex_t ifindex);
/* Sets the name and adds to name list */
@@ -575,9 +576,9 @@ connected_add_by_prefix(struct interface *, struct prefix *, struct prefix *);
extern struct connected *connected_delete_by_prefix(struct interface *,
struct prefix *);
extern struct connected *connected_lookup_prefix(struct interface *,
- struct prefix *);
+ const struct prefix *);
extern struct connected *connected_lookup_prefix_exact(struct interface *,
- struct prefix *);
+ const struct prefix *);
extern unsigned int connected_count_by_family(struct interface *, int family);
extern struct nbr_connected *nbr_connected_new(void);
extern void nbr_connected_free(struct nbr_connected *);
diff --git a/lib/mpls.h b/lib/mpls.h
index 05cf2935e8..126dbf753d 100644
--- a/lib/mpls.h
+++ b/lib/mpls.h
@@ -127,7 +127,8 @@ enum lsp_types_t {
ZEBRA_LSP_LDP = 2, /* LDP LSP. */
ZEBRA_LSP_BGP = 3, /* BGP LSP. */
ZEBRA_LSP_OSPF_SR = 4,/* OSPF Segment Routing LSP. */
- ZEBRA_LSP_SHARP = 5, /* Identifier for test protocol */
+ ZEBRA_LSP_ISIS_SR = 5,/* IS-IS Segment Routing LSP. */
+ ZEBRA_LSP_SHARP = 6, /* Identifier for test protocol */
};
/* Functions for basic label operations. */
diff --git a/lib/netns_linux.c b/lib/netns_linux.c
index 98f359401e..e1c0159fc5 100644
--- a/lib/netns_linux.c
+++ b/lib/netns_linux.c
@@ -379,12 +379,20 @@ struct ns *ns_lookup(ns_id_t ns_id)
return ns_lookup_internal(ns_id);
}
-void ns_walk_func(int (*func)(struct ns *))
+void ns_walk_func(int (*func)(struct ns *,
+ void *param_in,
+ void **param_out),
+ void *param_in,
+ void **param_out)
{
struct ns *ns = NULL;
+ int ret;
- RB_FOREACH (ns, ns_head, &ns_tree)
- func(ns);
+ RB_FOREACH (ns, ns_head, &ns_tree) {
+ ret = func(ns, param_in, param_out);
+ if (ret == NS_WALK_STOP)
+ return;
+ }
}
const char *ns_get_name(struct ns *ns)
@@ -584,9 +592,33 @@ int ns_socket(int domain, int type, int protocol, ns_id_t ns_id)
return ret;
}
+/* if relative link_nsid matches default netns,
+ * then return default absolute netns value
+ * otherwise, return NS_UNKNOWN
+ */
+ns_id_t ns_id_get_absolute(ns_id_t ns_id_reference, ns_id_t link_nsid)
+{
+ struct ns *ns;
+
+ ns = ns_lookup(ns_id_reference);
+ if (!ns)
+ return NS_UNKNOWN;
+ if (ns->relative_default_ns != link_nsid)
+ return NS_UNKNOWN;
+ ns = ns_get_default();
+ assert(ns);
+ return ns->ns_id;
+}
+
ns_id_t ns_get_default_id(void)
{
if (default_ns)
return default_ns->ns_id;
return NS_DEFAULT_INTERNAL;
}
+
+struct ns *ns_get_default(void)
+{
+ return default_ns;
+}
+
diff --git a/lib/northbound_grpc.cpp b/lib/northbound_grpc.cpp
index 66bf05c1ab..2962a977eb 100644
--- a/lib/northbound_grpc.cpp
+++ b/lib/northbound_grpc.cpp
@@ -28,6 +28,7 @@
#include "lib_errors.h"
#include "northbound.h"
#include "northbound_db.h"
+#include "frr_pthread.h"
#include <iostream>
#include <sstream>
@@ -36,6 +37,8 @@
#define GRPC_DEFAULT_PORT 50051
+static void *grpc_pthread_start(void *arg);
+
/*
* NOTE: we can't use the FRR debugging infrastructure here since it uses
* atomics and C++ has a different atomics API. Enable gRPC debugging
@@ -43,14 +46,78 @@
*/
static bool nb_dbg_client_grpc = 1;
-static pthread_t grpc_pthread;
+static struct frr_pthread *fpt;
+
+/* Default frr_pthread attributes */
+static const struct frr_pthread_attr attr = {
+ .start = grpc_pthread_start,
+ .stop = NULL,
+};
+
+enum CallStatus { CREATE, PROCESS, FINISH };
+
+/* Thanks gooble */
+class RpcStateBase
+{
+ public:
+ virtual void doCallback() = 0;
+};
+
+class NorthboundImpl;
-class NorthboundImpl final : public frr::Northbound::Service
+template <typename Q, typename S> class RpcState : RpcStateBase
+{
+ public:
+ RpcState(NorthboundImpl *svc,
+ void (NorthboundImpl::*cb)(RpcState<Q, S> *))
+ : callback(cb), responder(&ctx), async_responder(&ctx),
+ service(svc){};
+
+ void doCallback() override
+ {
+ (service->*callback)(this);
+ }
+
+ grpc::ServerContext ctx;
+ Q request;
+ S response;
+ grpc::ServerAsyncResponseWriter<S> responder;
+ grpc::ServerAsyncWriter<S> async_responder;
+
+ NorthboundImpl *service;
+ void (NorthboundImpl::*callback)(RpcState<Q, S> *);
+
+ void *context;
+ CallStatus state = CREATE;
+};
+
+#define REQUEST_RPC(NAME) \
+ do { \
+ auto _rpcState = \
+ new RpcState<frr::NAME##Request, frr::NAME##Response>( \
+ this, &NorthboundImpl::Handle##NAME); \
+ _service->Request##NAME(&_rpcState->ctx, &_rpcState->request, \
+ &_rpcState->responder, _cq, _cq, \
+ _rpcState); \
+ } while (0)
+
+#define REQUEST_RPC_STREAMING(NAME) \
+ do { \
+ auto _rpcState = \
+ new RpcState<frr::NAME##Request, frr::NAME##Response>( \
+ this, &NorthboundImpl::Handle##NAME); \
+ _service->Request##NAME(&_rpcState->ctx, &_rpcState->request, \
+ &_rpcState->async_responder, _cq, _cq, \
+ _rpcState); \
+ } while (0)
+
+class NorthboundImpl
{
public:
NorthboundImpl(void)
{
_nextCandidateId = 0;
+ _service = new frr::Northbound::AsyncService();
}
~NorthboundImpl(void)
@@ -61,61 +128,135 @@ class NorthboundImpl final : public frr::Northbound::Service
delete_candidate(&it->second);
}
- grpc::Status
- GetCapabilities(grpc::ServerContext *context,
- frr::GetCapabilitiesRequest const *request,
- frr::GetCapabilitiesResponse *response) override
+ void Run(unsigned long port)
+ {
+ grpc::ServerBuilder builder;
+ std::stringstream server_address;
+
+ server_address << "0.0.0.0:" << port;
+
+ builder.AddListeningPort(server_address.str(),
+ grpc::InsecureServerCredentials());
+ builder.RegisterService(_service);
+
+ auto cq = builder.AddCompletionQueue();
+ _cq = cq.get();
+ auto _server = builder.BuildAndStart();
+
+ /* Schedule all RPC handlers */
+ REQUEST_RPC(GetCapabilities);
+ REQUEST_RPC(CreateCandidate);
+ REQUEST_RPC(DeleteCandidate);
+ REQUEST_RPC(UpdateCandidate);
+ REQUEST_RPC(EditCandidate);
+ REQUEST_RPC(LoadToCandidate);
+ REQUEST_RPC(Commit);
+ REQUEST_RPC(GetTransaction);
+ REQUEST_RPC(LockConfig);
+ REQUEST_RPC(UnlockConfig);
+ REQUEST_RPC(Execute);
+ REQUEST_RPC_STREAMING(Get);
+ REQUEST_RPC_STREAMING(ListTransactions);
+
+ zlog_notice("gRPC server listening on %s",
+ server_address.str().c_str());
+
+ /* Process inbound RPCs */
+ void *tag;
+ bool ok;
+ while (true) {
+ _cq->Next(&tag, &ok);
+ GPR_ASSERT(ok);
+ static_cast<RpcStateBase *>(tag)->doCallback();
+ tag = nullptr;
+ }
+ }
+
+ void HandleGetCapabilities(RpcState<frr::GetCapabilitiesRequest,
+ frr::GetCapabilitiesResponse> *tag)
{
if (nb_dbg_client_grpc)
zlog_debug("received RPC GetCapabilities()");
- // Response: string frr_version = 1;
- response->set_frr_version(FRR_VERSION);
+ switch (tag->state) {
+ case CREATE:
+ REQUEST_RPC(GetCapabilities);
+ tag->state = PROCESS;
+ case PROCESS: {
- // Response: bool rollback_support = 2;
+ // Response: string frr_version = 1;
+ tag->response.set_frr_version(FRR_VERSION);
+
+ // Response: bool rollback_support = 2;
#ifdef HAVE_CONFIG_ROLLBACKS
- response->set_rollback_support(true);
+ tag->response.set_rollback_support(true);
#else
- response->set_rollback_support(false);
+ tag->response.set_rollback_support(false);
#endif
- // Response: repeated ModuleData supported_modules = 3;
- struct yang_module *module;
- RB_FOREACH (module, yang_modules, &yang_modules) {
- auto m = response->add_supported_modules();
+ // Response: repeated ModuleData supported_modules = 3;
+ struct yang_module *module;
+ RB_FOREACH (module, yang_modules, &yang_modules) {
+ auto m = tag->response.add_supported_modules();
- m->set_name(module->name);
- if (module->info->rev_size)
- m->set_revision(module->info->rev[0].date);
- m->set_organization(module->info->org);
- }
+ m->set_name(module->name);
+ if (module->info->rev_size)
+ m->set_revision(
+ module->info->rev[0].date);
+ m->set_organization(module->info->org);
+ }
- // Response: repeated Encoding supported_encodings = 4;
- response->add_supported_encodings(frr::JSON);
- response->add_supported_encodings(frr::XML);
+ // Response: repeated Encoding supported_encodings = 4;
+ tag->response.add_supported_encodings(frr::JSON);
+ tag->response.add_supported_encodings(frr::XML);
- return grpc::Status::OK;
+ tag->responder.Finish(tag->response, grpc::Status::OK,
+ tag);
+ tag->state = FINISH;
+ break;
+ }
+ case FINISH:
+ delete tag;
+ }
}
- grpc::Status Get(grpc::ServerContext *context,
- frr::GetRequest const *request,
- grpc::ServerWriter<frr::GetResponse> *writer) override
+ void HandleGet(RpcState<frr::GetRequest, frr::GetResponse> *tag)
{
- // Request: DataType type = 1;
- int type = request->type();
- // Request: Encoding encoding = 2;
- frr::Encoding encoding = request->encoding();
- // Request: bool with_defaults = 3;
- bool with_defaults = request->with_defaults();
+ switch (tag->state) {
+ case CREATE: {
+ auto mypaths = new std::list<std::string>();
+ tag->context = mypaths;
+ auto paths = tag->request.path();
+ for (const std::string &path : paths) {
+ mypaths->push_back(std::string(path));
+ }
+ REQUEST_RPC_STREAMING(Get);
+ tag->state = PROCESS;
+ }
+ case PROCESS: {
+ // Request: DataType type = 1;
+ int type = tag->request.type();
+ // Request: Encoding encoding = 2;
+ frr::Encoding encoding = tag->request.encoding();
+ // Request: bool with_defaults = 3;
+ bool with_defaults = tag->request.with_defaults();
+
+ if (nb_dbg_client_grpc)
+ zlog_debug(
+ "received RPC Get(type: %u, encoding: %u, with_defaults: %u)",
+ type, encoding, with_defaults);
+
+ auto mypaths = static_cast<std::list<std::string> *>(
+ tag->context);
+
+ if (mypaths->empty()) {
+ tag->async_responder.Finish(grpc::Status::OK,
+ tag);
+ tag->state = FINISH;
+ return;
+ }
- if (nb_dbg_client_grpc)
- zlog_debug(
- "received RPC Get(type: %u, encoding: %u, with_defaults: %u)",
- type, encoding, with_defaults);
- // Request: repeated string path = 4;
- auto paths = request->path();
- for (const std::string &path : paths) {
frr::GetResponse response;
grpc::Status status;
@@ -124,391 +265,695 @@ class NorthboundImpl final : public frr::Northbound::Service
// Response: DataTree data = 2;
auto *data = response.mutable_data();
- data->set_encoding(request->encoding());
- status = get_path(data, path, type,
+ data->set_encoding(tag->request.encoding());
+ status = get_path(data, mypaths->back().c_str(), type,
encoding2lyd_format(encoding),
with_defaults);
// Something went wrong...
- if (!status.ok())
- return status;
+ if (!status.ok()) {
+ tag->async_responder.WriteAndFinish(
+ response, grpc::WriteOptions(), status,
+ tag);
+ tag->state = FINISH;
+ return;
+ }
- writer->Write(response);
- }
+ mypaths->pop_back();
- if (nb_dbg_client_grpc)
- zlog_debug("received RPC Get() end");
+ tag->async_responder.Write(response, tag);
- return grpc::Status::OK;
+ break;
+ }
+ case FINISH:
+ if (nb_dbg_client_grpc)
+ zlog_debug("received RPC Get() end");
+
+ delete static_cast<std::list<std::string> *>(
+ tag->context);
+ delete tag;
+ }
}
- grpc::Status
- CreateCandidate(grpc::ServerContext *context,
- frr::CreateCandidateRequest const *request,
- frr::CreateCandidateResponse *response) override
+ void HandleCreateCandidate(RpcState<frr::CreateCandidateRequest,
+ frr::CreateCandidateResponse> *tag)
{
if (nb_dbg_client_grpc)
zlog_debug("received RPC CreateCandidate()");
- struct candidate *candidate = create_candidate();
- if (!candidate)
- return grpc::Status(
- grpc::StatusCode::RESOURCE_EXHAUSTED,
- "Can't create candidate configuration");
+ switch (tag->state) {
+ case CREATE:
+ REQUEST_RPC(CreateCandidate);
+ tag->state = PROCESS;
+ case PROCESS: {
+ struct candidate *candidate = create_candidate();
+ if (!candidate) {
+ tag->responder.Finish(
+ tag->response,
+ grpc::Status(
+ grpc::StatusCode::
+ RESOURCE_EXHAUSTED,
+ "Can't create candidate configuration"),
+ tag);
+ } else {
+ tag->response.set_candidate_id(candidate->id);
+ tag->responder.Finish(tag->response,
+ grpc::Status::OK, tag);
+ }
- // Response: uint32 candidate_id = 1;
- response->set_candidate_id(candidate->id);
+ tag->state = FINISH;
- return grpc::Status::OK;
+ break;
+ }
+ case FINISH:
+ delete tag;
+ }
}
- grpc::Status
- DeleteCandidate(grpc::ServerContext *context,
- frr::DeleteCandidateRequest const *request,
- frr::DeleteCandidateResponse *response) override
+ void HandleDeleteCandidate(RpcState<frr::DeleteCandidateRequest,
+ frr::DeleteCandidateResponse> *tag)
{
- // Request: uint32 candidate_id = 1;
- uint32_t candidate_id = request->candidate_id();
-
- if (nb_dbg_client_grpc)
- zlog_debug(
- "received RPC DeleteCandidate(candidate_id: %u)",
- candidate_id);
-
- struct candidate *candidate = get_candidate(candidate_id);
- if (!candidate)
- return grpc::Status(
- grpc::StatusCode::NOT_FOUND,
- "candidate configuration not found");
+ switch (tag->state) {
+ case CREATE:
+ REQUEST_RPC(DeleteCandidate);
+ tag->state = PROCESS;
+ case PROCESS: {
+
+ // Request: uint32 candidate_id = 1;
+ uint32_t candidate_id = tag->request.candidate_id();
+
+ if (nb_dbg_client_grpc)
+ zlog_debug(
+ "received RPC DeleteCandidate(candidate_id: %u)",
+ candidate_id);
+
+ struct candidate *candidate =
+ get_candidate(candidate_id);
+ if (!candidate) {
+ tag->responder.Finish(
+ tag->response,
+ grpc::Status(
+ grpc::StatusCode::NOT_FOUND,
+ "candidate configuration not found"),
+ tag);
+ tag->state = FINISH;
+ return;
+ } else {
+ delete_candidate(candidate);
+ tag->responder.Finish(tag->response,
+ grpc::Status::OK, tag);
+ tag->state = FINISH;
+ return;
+ }
+ tag->state = FINISH;
+ break;
+ }
+ case FINISH:
+ delete tag;
+ }
+ }
- delete_candidate(candidate);
+ void HandleUpdateCandidate(RpcState<frr::UpdateCandidateRequest,
+ frr::UpdateCandidateResponse> *tag)
+ {
+ switch (tag->state) {
+ case CREATE:
+ REQUEST_RPC(UpdateCandidate);
+ tag->state = PROCESS;
+ case PROCESS: {
+
+ // Request: uint32 candidate_id = 1;
+ uint32_t candidate_id = tag->request.candidate_id();
+
+ if (nb_dbg_client_grpc)
+ zlog_debug(
+ "received RPC UpdateCandidate(candidate_id: %u)",
+ candidate_id);
+
+ struct candidate *candidate =
+ get_candidate(candidate_id);
+
+ if (!candidate)
+ tag->responder.Finish(
+ tag->response,
+ grpc::Status(
+ grpc::StatusCode::NOT_FOUND,
+ "candidate configuration not found"),
+ tag);
+ else if (candidate->transaction)
+ tag->responder.Finish(
+ tag->response,
+ grpc::Status(
+ grpc::StatusCode::
+ FAILED_PRECONDITION,
+ "candidate is in the middle of a transaction"),
+ tag);
+ else if (nb_candidate_update(candidate->config)
+ != NB_OK)
+ tag->responder.Finish(
+ tag->response,
+ grpc::Status(
+ grpc::StatusCode::INTERNAL,
+ "failed to update candidate configuration"),
+ tag);
+
+ else
+ tag->responder.Finish(tag->response,
+ grpc::Status::OK, tag);
+
+ tag->state = FINISH;
- return grpc::Status::OK;
+ break;
+ }
+ case FINISH:
+ delete tag;
+ }
}
- grpc::Status
- UpdateCandidate(grpc::ServerContext *context,
- frr::UpdateCandidateRequest const *request,
- frr::UpdateCandidateResponse *response) override
+ void HandleEditCandidate(RpcState<frr::EditCandidateRequest,
+ frr::EditCandidateResponse> *tag)
{
- // Request: uint32 candidate_id = 1;
- uint32_t candidate_id = request->candidate_id();
+ switch (tag->state) {
+ case CREATE:
+ REQUEST_RPC(EditCandidate);
+ tag->state = PROCESS;
+ case PROCESS: {
+
+ // Request: uint32 candidate_id = 1;
+ uint32_t candidate_id = tag->request.candidate_id();
+
+ if (nb_dbg_client_grpc)
+ zlog_debug(
+ "received RPC EditCandidate(candidate_id: %u)",
+ candidate_id);
+
+ struct candidate *candidate =
+ get_candidate(candidate_id);
+
+ if (!candidate) {
+ tag->responder.Finish(
+ tag->response,
+ grpc::Status(
+ grpc::StatusCode::NOT_FOUND,
+ "candidate configuration not found"),
+ tag);
+ tag->state = FINISH;
+ break;
+ }
- if (nb_dbg_client_grpc)
- zlog_debug(
- "received RPC UpdateCandidate(candidate_id: %u)",
- candidate_id);
+ struct nb_config *candidate_tmp =
+ nb_config_dup(candidate->config);
+
+ auto pvs = tag->request.update();
+ for (const frr::PathValue &pv : pvs) {
+ if (yang_dnode_edit(candidate_tmp->dnode,
+ pv.path(), pv.value())
+ != 0) {
+ nb_config_free(candidate_tmp);
+
+ tag->responder.Finish(
+ tag->response,
+ grpc::Status(
+ grpc::StatusCode::
+ INVALID_ARGUMENT,
+ "Failed to update \""
+ + pv.path()
+ + "\""),
+ tag);
+
+ tag->state = FINISH;
+ return;
+ }
+ }
- struct candidate *candidate = get_candidate(candidate_id);
- if (!candidate)
- return grpc::Status(
- grpc::StatusCode::NOT_FOUND,
- "candidate configuration not found");
+ pvs = tag->request.delete_();
+ for (const frr::PathValue &pv : pvs) {
+ if (yang_dnode_delete(candidate_tmp->dnode,
+ pv.path())
+ != 0) {
+ nb_config_free(candidate_tmp);
+ tag->responder.Finish(
+ tag->response,
+ grpc::Status(
+ grpc::StatusCode::
+ INVALID_ARGUMENT,
+ "Failed to remove \""
+ + pv.path()
+ + "\""),
+ tag);
+ tag->state = FINISH;
+ return;
+ }
+ }
- if (candidate->transaction)
- return grpc::Status(
- grpc::StatusCode::FAILED_PRECONDITION,
- "candidate is in the middle of a transaction");
+ // No errors, accept all changes.
+ nb_config_replace(candidate->config, candidate_tmp,
+ false);
- if (nb_candidate_update(candidate->config) != NB_OK)
- return grpc::Status(
- grpc::StatusCode::INTERNAL,
- "failed to update candidate configuration");
+ tag->responder.Finish(tag->response, grpc::Status::OK,
+ tag);
- return grpc::Status::OK;
+ tag->state = FINISH;
+
+ break;
+ }
+ case FINISH:
+ delete tag;
+ }
}
- grpc::Status
- EditCandidate(grpc::ServerContext *context,
- frr::EditCandidateRequest const *request,
- frr::EditCandidateResponse *response) override
+ void HandleLoadToCandidate(RpcState<frr::LoadToCandidateRequest,
+ frr::LoadToCandidateResponse> *tag)
{
- // Request: uint32 candidate_id = 1;
- uint32_t candidate_id = request->candidate_id();
-
- if (nb_dbg_client_grpc)
- zlog_debug(
- "received RPC EditCandidate(candidate_id: %u)",
- candidate_id);
-
- struct candidate *candidate = get_candidate(candidate_id);
- if (!candidate)
- return grpc::Status(
- grpc::StatusCode::NOT_FOUND,
- "candidate configuration not found");
-
- // Create a copy of the candidate. For consistency, we need to
- // ensure that either all changes are accepted or none are (in
- // the event of an error).
- struct nb_config *candidate_tmp =
- nb_config_dup(candidate->config);
-
- auto pvs = request->update();
- for (const frr::PathValue &pv : pvs) {
- if (yang_dnode_edit(candidate_tmp->dnode, pv.path(),
- pv.value())
- != 0) {
- nb_config_free(candidate_tmp);
- return grpc::Status(
- grpc::StatusCode::INVALID_ARGUMENT,
- "Failed to update \"" + pv.path()
- + "\"");
+ switch (tag->state) {
+ case CREATE:
+ REQUEST_RPC(LoadToCandidate);
+ tag->state = PROCESS;
+ case PROCESS: {
+ // Request: uint32 candidate_id = 1;
+ uint32_t candidate_id = tag->request.candidate_id();
+
+ if (nb_dbg_client_grpc)
+ zlog_debug(
+ "received RPC LoadToCandidate(candidate_id: %u)",
+ candidate_id);
+
+ // Request: LoadType type = 2;
+ int load_type = tag->request.type();
+ // Request: DataTree config = 3;
+ auto config = tag->request.config();
+
+
+ struct candidate *candidate =
+ get_candidate(candidate_id);
+
+ if (!candidate) {
+ tag->responder.Finish(
+ tag->response,
+ grpc::Status(
+ grpc::StatusCode::NOT_FOUND,
+ "candidate configuration not found"),
+ tag);
+ tag->state = FINISH;
+ return;
}
- }
- pvs = request->delete_();
- for (const frr::PathValue &pv : pvs) {
- if (yang_dnode_delete(candidate_tmp->dnode, pv.path())
- != 0) {
- nb_config_free(candidate_tmp);
- return grpc::Status(
- grpc::StatusCode::INVALID_ARGUMENT,
- "Failed to remove \"" + pv.path()
- + "\"");
+ struct lyd_node *dnode =
+ dnode_from_data_tree(&config, true);
+ if (!dnode) {
+ tag->responder.Finish(
+ tag->response,
+ grpc::Status(
+ grpc::StatusCode::INTERNAL,
+ "Failed to parse the configuration"),
+ tag);
+ tag->state = FINISH;
+ return;
}
- }
- // No errors, accept all changes.
- nb_config_replace(candidate->config, candidate_tmp, false);
+ struct nb_config *loaded_config = nb_config_new(dnode);
+
+ if (load_type == frr::LoadToCandidateRequest::REPLACE)
+ nb_config_replace(candidate->config,
+ loaded_config, false);
+ else if (nb_config_merge(candidate->config,
+ loaded_config, false)
+ != NB_OK) {
+ tag->responder.Finish(
+ tag->response,
+ grpc::Status(
+ grpc::StatusCode::INTERNAL,
+ "Failed to merge the loaded configuration"),
+ tag);
+ tag->state = FINISH;
+ return;
+ }
- return grpc::Status::OK;
+ tag->responder.Finish(tag->response, grpc::Status::OK,
+ tag);
+ tag->state = FINISH;
+ break;
+ }
+ case FINISH:
+ delete tag;
+ }
}
- grpc::Status
- LoadToCandidate(grpc::ServerContext *context,
- frr::LoadToCandidateRequest const *request,
- frr::LoadToCandidateResponse *response) override
+ void
+ HandleCommit(RpcState<frr::CommitRequest, frr::CommitResponse> *tag)
{
- // Request: uint32 candidate_id = 1;
- uint32_t candidate_id = request->candidate_id();
- // Request: LoadType type = 2;
- int load_type = request->type();
- // Request: DataTree config = 3;
- auto config = request->config();
-
- if (nb_dbg_client_grpc)
- zlog_debug(
- "received RPC LoadToCandidate(candidate_id: %u)",
- candidate_id);
-
- struct candidate *candidate = get_candidate(candidate_id);
- if (!candidate)
- return grpc::Status(
- grpc::StatusCode::NOT_FOUND,
- "candidate configuration not found");
+ switch (tag->state) {
+ case CREATE:
+ REQUEST_RPC(Commit);
+ tag->state = PROCESS;
+ case PROCESS: {
+ // Request: uint32 candidate_id = 1;
+ uint32_t candidate_id = tag->request.candidate_id();
+ if (nb_dbg_client_grpc)
+ zlog_debug(
+ "received RPC Commit(candidate_id: %u)",
+ candidate_id);
+
+ // Request: Phase phase = 2;
+ int phase = tag->request.phase();
+ // Request: string comment = 3;
+ const std::string comment = tag->request.comment();
+
+ // Find candidate configuration.
+ struct candidate *candidate =
+ get_candidate(candidate_id);
+ if (!candidate) {
+ tag->responder.Finish(
+ tag->response,
+ grpc::Status(
+ grpc::StatusCode::NOT_FOUND,
+ "candidate configuration not found"),
+ tag);
+ tag->state = FINISH;
+ return;
+ }
- struct lyd_node *dnode = dnode_from_data_tree(&config, true);
- if (!dnode)
- return grpc::Status(
- grpc::StatusCode::INTERNAL,
- "Failed to parse the configuration");
+ int ret = NB_OK;
+ uint32_t transaction_id = 0;
+
+ // Check for misuse of the two-phase commit protocol.
+ switch (phase) {
+ case frr::CommitRequest::PREPARE:
+ case frr::CommitRequest::ALL:
+ if (candidate->transaction) {
+ tag->responder.Finish(
+ tag->response,
+ grpc::Status(
+ grpc::StatusCode::
+ FAILED_PRECONDITION,
+ "candidate is in the middle of a transaction"),
+ tag);
+ tag->state = FINISH;
+ return;
+ }
+ break;
+ case frr::CommitRequest::ABORT:
+ case frr::CommitRequest::APPLY:
+ if (!candidate->transaction) {
+ tag->responder.Finish(
+ tag->response,
+ grpc::Status(
+ grpc::StatusCode::
+ FAILED_PRECONDITION,
+ "no transaction in progress"),
+ tag);
+ tag->state = FINISH;
+ return;
+ }
+ break;
+ default:
+ break;
+ }
- struct nb_config *loaded_config = nb_config_new(dnode);
- if (load_type == frr::LoadToCandidateRequest::REPLACE)
- nb_config_replace(candidate->config, loaded_config,
- false);
- else if (nb_config_merge(candidate->config, loaded_config,
- false)
- != NB_OK)
- return grpc::Status(
- grpc::StatusCode::INTERNAL,
- "Failed to merge the loaded configuration");
+ // Execute the user request.
+ switch (phase) {
+ case frr::CommitRequest::VALIDATE:
+ ret = nb_candidate_validate(candidate->config);
+ break;
+ case frr::CommitRequest::PREPARE:
+ ret = nb_candidate_commit_prepare(
+ candidate->config, NB_CLIENT_GRPC, NULL,
+ comment.c_str(),
+ &candidate->transaction);
+ break;
+ case frr::CommitRequest::ABORT:
+ nb_candidate_commit_abort(
+ candidate->transaction);
+ break;
+ case frr::CommitRequest::APPLY:
+ nb_candidate_commit_apply(
+ candidate->transaction, true,
+ &transaction_id);
+ break;
+ case frr::CommitRequest::ALL:
+ ret = nb_candidate_commit(
+ candidate->config, NB_CLIENT_GRPC, NULL,
+ true, comment.c_str(), &transaction_id);
+ break;
+ }
- return grpc::Status::OK;
- }
+ // Map northbound error codes to gRPC error codes.
+ switch (ret) {
+ case NB_ERR_NO_CHANGES:
+ tag->responder.Finish(
+ tag->response,
+ grpc::Status(
+ grpc::StatusCode::ABORTED,
+ "No configuration changes detected"),
+ tag);
+ tag->state = FINISH;
+ return;
+ case NB_ERR_LOCKED:
+ tag->responder.Finish(
+ tag->response,
+ grpc::Status(
+ grpc::StatusCode::UNAVAILABLE,
+ "There's already a transaction in progress"),
+ tag);
+ tag->state = FINISH;
+ return;
+ case NB_ERR_VALIDATION:
+ tag->responder.Finish(
+ tag->response,
+ grpc::Status(grpc::StatusCode::
+ INVALID_ARGUMENT,
+ "Validation error"),
+ tag);
+ tag->state = FINISH;
+ return;
+ case NB_ERR_RESOURCE:
+ tag->responder.Finish(
+ tag->response,
+ grpc::Status(
+ grpc::StatusCode::
+ RESOURCE_EXHAUSTED,
+ "Failed do allocate resources"),
+ tag);
+ tag->state = FINISH;
+ return;
+ case NB_ERR:
+ tag->responder.Finish(
+ tag->response,
+ grpc::Status(grpc::StatusCode::INTERNAL,
+ "Internal error"),
+ tag);
+ tag->state = FINISH;
+ return;
+ default:
+ break;
+ }
- grpc::Status Commit(grpc::ServerContext *context,
- frr::CommitRequest const *request,
- frr::CommitResponse *response) override
- {
- // Request: uint32 candidate_id = 1;
- uint32_t candidate_id = request->candidate_id();
- // Request: Phase phase = 2;
- int phase = request->phase();
- // Request: string comment = 3;
- const std::string comment = request->comment();
+ // Response: uint32 transaction_id = 1;
+ if (transaction_id)
+ tag->response.set_transaction_id(
+ transaction_id);
- if (nb_dbg_client_grpc)
- zlog_debug("received RPC Commit(candidate_id: %u)",
- candidate_id);
-
- // Find candidate configuration.
- struct candidate *candidate = get_candidate(candidate_id);
- if (!candidate)
- return grpc::Status(
- grpc::StatusCode::NOT_FOUND,
- "candidate configuration not found");
-
- int ret = NB_OK;
- uint32_t transaction_id = 0;
-
- // Check for misuse of the two-phase commit protocol.
- switch (phase) {
- case frr::CommitRequest::PREPARE:
- case frr::CommitRequest::ALL:
- if (candidate->transaction)
- return grpc::Status(
- grpc::StatusCode::FAILED_PRECONDITION,
- "pending transaction in progress");
- break;
- case frr::CommitRequest::ABORT:
- case frr::CommitRequest::APPLY:
- if (!candidate->transaction)
- return grpc::Status(
- grpc::StatusCode::FAILED_PRECONDITION,
- "no transaction in progress");
- break;
- default:
- break;
- }
+ tag->responder.Finish(tag->response, grpc::Status::OK,
+ tag);
+ tag->state = FINISH;
- // Execute the user request.
- switch (phase) {
- case frr::CommitRequest::VALIDATE:
- ret = nb_candidate_validate(candidate->config);
- break;
- case frr::CommitRequest::PREPARE:
- ret = nb_candidate_commit_prepare(
- candidate->config, NB_CLIENT_GRPC, NULL,
- comment.c_str(), &candidate->transaction);
- break;
- case frr::CommitRequest::ABORT:
- nb_candidate_commit_abort(candidate->transaction);
- break;
- case frr::CommitRequest::APPLY:
- nb_candidate_commit_apply(candidate->transaction, true,
- &transaction_id);
- break;
- case frr::CommitRequest::ALL:
- ret = nb_candidate_commit(
- candidate->config, NB_CLIENT_GRPC, NULL, true,
- comment.c_str(), &transaction_id);
break;
}
-
- // Map northbound error codes to gRPC error codes.
- switch (ret) {
- case NB_ERR_NO_CHANGES:
- return grpc::Status(
- grpc::StatusCode::ABORTED,
- "No configuration changes detected");
- case NB_ERR_LOCKED:
- return grpc::Status(
- grpc::StatusCode::UNAVAILABLE,
- "There's already a transaction in progress");
- case NB_ERR_VALIDATION:
- return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
- "Validation error");
- case NB_ERR_RESOURCE:
- return grpc::Status(
- grpc::StatusCode::RESOURCE_EXHAUSTED,
- "Failed do allocate resources");
- case NB_ERR:
- return grpc::Status(grpc::StatusCode::INTERNAL,
- "Internal error");
- default:
- break;
+ case FINISH:
+ delete tag;
}
-
- // Response: uint32 transaction_id = 1;
- if (transaction_id)
- response->set_transaction_id(transaction_id);
-
- return grpc::Status::OK;
}
- grpc::Status
- ListTransactions(grpc::ServerContext *context,
- frr::ListTransactionsRequest const *request,
- grpc::ServerWriter<frr::ListTransactionsResponse>
- *writer) override
+ void
+ HandleListTransactions(RpcState<frr::ListTransactionsRequest,
+ frr::ListTransactionsResponse> *tag)
{
if (nb_dbg_client_grpc)
zlog_debug("received RPC ListTransactions()");
- nb_db_transactions_iterate(list_transactions_cb, writer);
+ switch (tag->state) {
+ case CREATE:
+ REQUEST_RPC_STREAMING(ListTransactions);
+ tag->context = new std::list<std::tuple<
+ int, std::string, std::string, std::string>>();
+ nb_db_transactions_iterate(list_transactions_cb,
+ tag->context);
+ tag->state = PROCESS;
+ case PROCESS: {
+ auto list = static_cast<std::list<std::tuple<
+ int, std::string, std::string, std::string>> *>(
+ tag->context);
+ if (list->empty()) {
+ tag->async_responder.Finish(grpc::Status::OK,
+ tag);
+ tag->state = FINISH;
+ return;
+ }
+ auto item = list->back();
- return grpc::Status::OK;
- }
- grpc::Status
- GetTransaction(grpc::ServerContext *context,
- frr::GetTransactionRequest const *request,
- frr::GetTransactionResponse *response) override
- {
- struct nb_config *nb_config;
+ frr::ListTransactionsResponse response;
- // Request: uint32 transaction_id = 1;
- uint32_t transaction_id = request->transaction_id();
- // Request: Encoding encoding = 2;
- frr::Encoding encoding = request->encoding();
- // Request: bool with_defaults = 3;
- bool with_defaults = request->with_defaults();
+ // Response: uint32 id = 1;
+ response.set_id(std::get<0>(item));
- if (nb_dbg_client_grpc)
- zlog_debug(
- "received RPC GetTransaction(transaction_id: %u, encoding: %u)",
- transaction_id, encoding);
+ // Response: string client = 2;
+ response.set_client(std::get<1>(item).c_str());
- // Load configuration from the transactions database.
- nb_config = nb_db_transaction_load(transaction_id);
- if (!nb_config)
- return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
- "Transaction not found");
+ // Response: string date = 3;
+ response.set_date(std::get<2>(item).c_str());
- // Response: DataTree config = 1;
- auto config = response->mutable_config();
- config->set_encoding(encoding);
+ // Response: string comment = 4;
+ response.set_comment(std::get<3>(item).c_str());
- // Dump data using the requested format.
- if (data_tree_from_dnode(config, nb_config->dnode,
- encoding2lyd_format(encoding),
- with_defaults)
- != 0) {
- nb_config_free(nb_config);
- return grpc::Status(grpc::StatusCode::INTERNAL,
- "Failed to dump data");
+ list->pop_back();
+
+ tag->async_responder.Write(response, tag);
+ break;
+ }
+ case FINISH:
+ delete static_cast<std::list<std::tuple<
+ int, std::string, std::string, std::string>> *>(
+ tag->context);
+ delete tag;
}
+ }
- nb_config_free(nb_config);
+ void HandleGetTransaction(RpcState<frr::GetTransactionRequest,
+ frr::GetTransactionResponse> *tag)
+ {
+ switch (tag->state) {
+ case CREATE:
+ REQUEST_RPC(GetTransaction);
+ tag->state = PROCESS;
+ case PROCESS: {
+ // Request: uint32 transaction_id = 1;
+ uint32_t transaction_id = tag->request.transaction_id();
+ // Request: Encoding encoding = 2;
+ frr::Encoding encoding = tag->request.encoding();
+ // Request: bool with_defaults = 3;
+ bool with_defaults = tag->request.with_defaults();
+
+ if (nb_dbg_client_grpc)
+ zlog_debug(
+ "received RPC GetTransaction(transaction_id: %u, encoding: %u)",
+ transaction_id, encoding);
+
+ struct nb_config *nb_config;
+
+ // Load configuration from the transactions database.
+ nb_config = nb_db_transaction_load(transaction_id);
+ if (!nb_config) {
+ tag->responder.Finish(
+ tag->response,
+ grpc::Status(grpc::StatusCode::
+ INVALID_ARGUMENT,
+ "Transaction not found"),
+ tag);
+ tag->state = FINISH;
+ return;
+ }
- return grpc::Status::OK;
+ // Response: DataTree config = 1;
+ auto config = tag->response.mutable_config();
+ config->set_encoding(encoding);
+
+ // Dump data using the requested format.
+ if (data_tree_from_dnode(config, nb_config->dnode,
+ encoding2lyd_format(encoding),
+ with_defaults)
+ != 0) {
+ nb_config_free(nb_config);
+ tag->responder.Finish(
+ tag->response,
+ grpc::Status(grpc::StatusCode::INTERNAL,
+ "Failed to dump data"),
+ tag);
+ tag->state = FINISH;
+ return;
+ }
+
+ nb_config_free(nb_config);
+
+ tag->responder.Finish(tag->response, grpc::Status::OK,
+ tag);
+ tag->state = FINISH;
+ break;
+ }
+ case FINISH:
+ delete tag;
+ }
}
- grpc::Status LockConfig(grpc::ServerContext *context,
- frr::LockConfigRequest const *request,
- frr::LockConfigResponse *response) override
+ void HandleLockConfig(
+ RpcState<frr::LockConfigRequest, frr::LockConfigResponse> *tag)
{
if (nb_dbg_client_grpc)
zlog_debug("received RPC LockConfig()");
- if (nb_running_lock(NB_CLIENT_GRPC, NULL))
- return grpc::Status(
- grpc::StatusCode::FAILED_PRECONDITION,
- "running configuration is locked already");
+ switch (tag->state) {
+ case CREATE:
+ REQUEST_RPC(LockConfig);
+ tag->state = PROCESS;
+ case PROCESS: {
+ if (nb_running_lock(NB_CLIENT_GRPC, NULL)) {
+ tag->responder.Finish(
+ tag->response,
+ grpc::Status(
+ grpc::StatusCode::
+ FAILED_PRECONDITION,
+ "running configuration is locked already"),
+ tag);
+ tag->state = FINISH;
+ return;
+ }
- return grpc::Status::OK;
+ tag->responder.Finish(tag->response, grpc::Status::OK,
+ tag);
+ tag->state = FINISH;
+ break;
+ }
+ case FINISH:
+ delete tag;
+ }
}
- grpc::Status UnlockConfig(grpc::ServerContext *context,
- frr::UnlockConfigRequest const *request,
- frr::UnlockConfigResponse *response) override
+ void HandleUnlockConfig(RpcState<frr::UnlockConfigRequest,
+ frr::UnlockConfigResponse> *tag)
{
if (nb_dbg_client_grpc)
zlog_debug("received RPC UnlockConfig()");
- if (nb_running_unlock(NB_CLIENT_GRPC, NULL))
- return grpc::Status(
- grpc::StatusCode::FAILED_PRECONDITION,
- "failed to unlock the running configuration");
+ switch (tag->state) {
+ case CREATE:
+ REQUEST_RPC(UnlockConfig);
+ tag->state = PROCESS;
+ case PROCESS: {
+ if (nb_running_unlock(NB_CLIENT_GRPC, NULL)) {
+ tag->responder.Finish(
+ tag->response,
+ grpc::Status(
+ grpc::StatusCode::
+ FAILED_PRECONDITION,
+ "failed to unlock the running configuration"),
+ tag);
+ tag->state = FINISH;
+ return;
+ }
- return grpc::Status::OK;
+ tag->responder.Finish(tag->response, grpc::Status::OK,
+ tag);
+ tag->state = FINISH;
+ break;
+ }
+ case FINISH:
+ delete tag;
+ }
}
- grpc::Status Execute(grpc::ServerContext *context,
- frr::ExecuteRequest const *request,
- frr::ExecuteResponse *response) override
+ void
+ HandleExecute(RpcState<frr::ExecuteRequest, frr::ExecuteResponse> *tag)
{
struct nb_node *nb_node;
struct list *input_list;
@@ -517,61 +962,98 @@ class NorthboundImpl final : public frr::Northbound::Service
struct yang_data *data;
const char *xpath;
- // Request: string path = 1;
- xpath = request->path().c_str();
+ switch (tag->state) {
+ case CREATE:
+ REQUEST_RPC(Execute);
+ tag->state = PROCESS;
+ case PROCESS: {
+ // Request: string path = 1;
+ xpath = tag->request.path().c_str();
+
+ if (nb_dbg_client_grpc)
+ zlog_debug("received RPC Execute(path: \"%s\")",
+ xpath);
+
+ if (tag->request.path().empty()) {
+ tag->responder.Finish(
+ tag->response,
+ grpc::Status(grpc::StatusCode::
+ INVALID_ARGUMENT,
+ "Data path is empty"),
+ tag);
+ tag->state = FINISH;
+ return;
+ }
- if (nb_dbg_client_grpc)
- zlog_debug("received RPC Execute(path: \"%s\")", xpath);
+ nb_node = nb_node_find(xpath);
+ if (!nb_node) {
+ tag->responder.Finish(
+ tag->response,
+ grpc::Status(grpc::StatusCode::
+ INVALID_ARGUMENT,
+ "Unknown data path"),
+ tag);
+ tag->state = FINISH;
+ return;
+ }
- if (request->path().empty())
- return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
- "Data path is empty");
+ input_list = yang_data_list_new();
+ output_list = yang_data_list_new();
- nb_node = nb_node_find(xpath);
- if (!nb_node)
- return grpc::Status(grpc::StatusCode::INVALID_ARGUMENT,
- "Unknown data path");
+ // Read input parameters.
+ auto input = tag->request.input();
+ for (const frr::PathValue &pv : input) {
+ // Request: repeated PathValue input = 2;
+ data = yang_data_new(pv.path().c_str(),
+ pv.value().c_str());
+ listnode_add(input_list, data);
+ }
- input_list = yang_data_list_new();
- output_list = yang_data_list_new();
+ // Execute callback registered for this XPath.
+ if (nb_callback_rpc(nb_node, xpath, input_list,
+ output_list)
+ != NB_OK) {
+ flog_warn(EC_LIB_NB_CB_RPC,
+ "%s: rpc callback failed: %s",
+ __func__, xpath);
+ list_delete(&input_list);
+ list_delete(&output_list);
+
+ tag->responder.Finish(
+ tag->response,
+ grpc::Status(grpc::StatusCode::INTERNAL,
+ "RPC failed"),
+ tag);
+ tag->state = FINISH;
+ return;
+ }
- // Read input parameters.
- auto input = request->input();
- for (const frr::PathValue &pv : input) {
- // Request: repeated PathValue input = 2;
- data = yang_data_new(pv.path().c_str(),
- pv.value().c_str());
- listnode_add(input_list, data);
- }
+ // Process output parameters.
+ for (ALL_LIST_ELEMENTS_RO(output_list, node, data)) {
+ // Response: repeated PathValue output = 1;
+ frr::PathValue *pv = tag->response.add_output();
+ pv->set_path(data->xpath);
+ pv->set_value(data->value);
+ }
- // Execute callback registered for this XPath.
- if (nb_callback_rpc(nb_node, xpath, input_list, output_list)
- != NB_OK) {
- flog_warn(EC_LIB_NB_CB_RPC,
- "%s: rpc callback failed: %s", __func__,
- xpath);
+ // Release memory.
list_delete(&input_list);
list_delete(&output_list);
- return grpc::Status(grpc::StatusCode::INTERNAL,
- "RPC failed");
- }
- // Process output parameters.
- for (ALL_LIST_ELEMENTS_RO(output_list, node, data)) {
- // Response: repeated PathValue output = 1;
- frr::PathValue *pv = response->add_output();
- pv->set_path(data->xpath);
- pv->set_value(data->value);
+ tag->responder.Finish(tag->response, grpc::Status::OK,
+ tag);
+ tag->state = FINISH;
+ break;
+ }
+ case FINISH:
+ delete tag;
}
-
- // Release memory.
- list_delete(&input_list);
- list_delete(&output_list);
-
- return grpc::Status::OK;
}
private:
+ frr::Northbound::AsyncService *_service;
+ grpc::ServerCompletionQueue *_cq;
+
struct candidate {
uint32_t id;
struct nb_config *config;
@@ -640,24 +1122,12 @@ class NorthboundImpl final : public frr::Northbound::Service
const char *client_name,
const char *date, const char *comment)
{
- grpc::ServerWriter<frr::ListTransactionsResponse> *writer =
- static_cast<grpc::ServerWriter<
- frr::ListTransactionsResponse> *>(arg);
- frr::ListTransactionsResponse response;
-
- // Response: uint32 id = 1;
- response.set_id(transaction_id);
-
- // Response: string client = 2;
- response.set_client(client_name);
- // Response: string date = 3;
- response.set_date(date);
-
- // Response: string comment = 4;
- response.set_comment(comment);
-
- writer->Write(response);
+ auto list = static_cast<std::list<std::tuple<
+ int, std::string, std::string, std::string>> *>(arg);
+ list->push_back(std::make_tuple(
+ transaction_id, std::string(client_name),
+ std::string(date), std::string(comment)));
}
static int data_tree_from_dnode(frr::DataTree *dt,
@@ -844,42 +1314,37 @@ class NorthboundImpl final : public frr::Northbound::Service
static void *grpc_pthread_start(void *arg)
{
- unsigned long *port = static_cast<unsigned long *>(arg);
- NorthboundImpl service;
- std::stringstream server_address;
-
- server_address << "0.0.0.0:" << *port;
+ struct frr_pthread *fpt = static_cast<frr_pthread *>(arg);
+ unsigned long *port = static_cast<unsigned long *>(fpt->data);
- grpc::ServerBuilder builder;
- builder.AddListeningPort(server_address.str(),
- grpc::InsecureServerCredentials());
- builder.RegisterService(&service);
+ frr_pthread_set_name(fpt);
- std::unique_ptr<grpc::Server> server(builder.BuildAndStart());
-
- zlog_notice("gRPC server listening on %s",
- server_address.str().c_str());
-
- server->Wait();
+ NorthboundImpl nb;
+ nb.Run(*port);
return NULL;
}
static int frr_grpc_init(unsigned long *port)
{
+ fpt = frr_pthread_new(&attr, "frr-grpc", "frr-grpc");
+ fpt->data = static_cast<void *>(port);
+
/* Create a pthread for gRPC since it runs its own event loop. */
- if (pthread_create(&grpc_pthread, NULL, grpc_pthread_start, port)) {
+ if (frr_pthread_run(fpt, NULL) < 0) {
flog_err(EC_LIB_SYSTEM_CALL, "%s: error creating pthread: %s",
__func__, safe_strerror(errno));
return -1;
}
- pthread_detach(grpc_pthread);
+ pthread_detach(fpt->thread);
return 0;
}
static int frr_grpc_finish(void)
{
+ if (fpt)
+ frr_pthread_destroy(fpt);
// TODO: cancel the gRPC pthreads gracefully.
return 0;
@@ -918,6 +1383,8 @@ static int frr_grpc_module_very_late_init(struct thread *thread)
if (frr_grpc_init(&port) < 0)
goto error;
+ return 0;
+
error:
flog_err(EC_LIB_GRPC_INIT, "failed to initialize the gRPC module");
return -1;
diff --git a/lib/ns.h b/lib/ns.h
index 20e0a38e3b..286ff5b295 100644
--- a/lib/ns.h
+++ b/lib/ns.h
@@ -53,6 +53,11 @@ struct ns {
/* Identifier, mapped on the NSID value */
ns_id_t internal_ns_id;
+ /* Identifier, value of NSID of default netns,
+ * relative value in that local netns
+ */
+ ns_id_t relative_default_ns;
+
/* Name */
char *name;
@@ -120,7 +125,14 @@ int ns_socket(int domain, int type, int protocol, ns_id_t ns_id);
extern char *ns_netns_pathname(struct vty *vty, const char *name);
/* Parse and execute a function on all the NETNS */
-extern void ns_walk_func(int (*func)(struct ns *));
+#define NS_WALK_CONTINUE 0
+#define NS_WALK_STOP 1
+
+extern void ns_walk_func(int (*func)(struct ns *,
+ void *,
+ void **),
+ void *param_in,
+ void **param_out);
/* API to get the NETNS name, from the ns pointer */
extern const char *ns_get_name(struct ns *ns);
@@ -174,7 +186,9 @@ extern struct ns *ns_lookup_name(const char *name);
*/
extern int ns_enable(struct ns *ns, void (*func)(ns_id_t, void *));
extern struct ns *ns_get_created(struct ns *ns, char *name, ns_id_t ns_id);
+extern ns_id_t ns_id_get_absolute(ns_id_t ns_id_reference, ns_id_t link_nsid);
extern void ns_disable(struct ns *ns);
+extern struct ns *ns_get_default(void);
#ifdef __cplusplus
}
diff --git a/lib/prefix.c b/lib/prefix.c
index 80fe0f54a9..112630e9c8 100644
--- a/lib/prefix.c
+++ b/lib/prefix.c
@@ -966,7 +966,7 @@ static const char *prefixevpn_prefix2str(const struct prefix_evpn *p, char *str,
family = is_evpn_prefix_ipaddr_v4(p)
? AF_INET
: AF_INET6;
- snprintf(str, size, "[%d]:[%u][%s/%d]/%d",
+ snprintf(str, size, "[%d]:[%u]:[%s/%d]/%d",
p->prefix.route_type,
p->prefix.prefix_addr.eth_tag,
inet_ntop(family,
diff --git a/lib/prefix.h b/lib/prefix.h
index f2952c38c3..4b2d90d63a 100644
--- a/lib/prefix.h
+++ b/lib/prefix.h
@@ -522,7 +522,7 @@ static inline int is_default_prefix(const struct prefix *p)
return 0;
}
-static inline int is_host_route(struct prefix *p)
+static inline int is_host_route(const struct prefix *p)
{
if (p->family == AF_INET)
return (p->prefixlen == IPV4_MAX_BITLEN);
diff --git a/lib/typerb.c b/lib/typerb.c
index 7e8cd9d8f7..092faa4cc9 100644
--- a/lib/typerb.c
+++ b/lib/typerb.c
@@ -377,12 +377,13 @@ struct typed_rb_entry *typed_rb_insert(struct rbt_tree *rbt,
}
/* Finds the node with the same key as elm */
-struct rb_entry *typed_rb_find(struct rbt_tree *rbt, const struct rb_entry *key,
+const struct rb_entry *typed_rb_find(const struct rbt_tree *rbt,
+ const struct rb_entry *key,
int (*cmpfn)(
const struct typed_rb_entry *a,
const struct typed_rb_entry *b))
{
- struct rb_entry *tmp = RBH_ROOT(rbt);
+ const struct rb_entry *tmp = RBH_ROOT(rbt);
int comp;
while (tmp != NULL) {
@@ -398,13 +399,13 @@ struct rb_entry *typed_rb_find(struct rbt_tree *rbt, const struct rb_entry *key,
return NULL;
}
-struct rb_entry *typed_rb_find_gteq(struct rbt_tree *rbt,
+const struct rb_entry *typed_rb_find_gteq(const struct rbt_tree *rbt,
const struct rb_entry *key,
int (*cmpfn)(
const struct typed_rb_entry *a,
const struct typed_rb_entry *b))
{
- struct rb_entry *tmp = RBH_ROOT(rbt), *best = NULL;
+ const struct rb_entry *tmp = RBH_ROOT(rbt), *best = NULL;
int comp;
while (tmp != NULL) {
@@ -421,13 +422,13 @@ struct rb_entry *typed_rb_find_gteq(struct rbt_tree *rbt,
return best;
}
-struct rb_entry *typed_rb_find_lt(struct rbt_tree *rbt,
+const struct rb_entry *typed_rb_find_lt(const struct rbt_tree *rbt,
const struct rb_entry *key,
int (*cmpfn)(
const struct typed_rb_entry *a,
const struct typed_rb_entry *b))
{
- struct rb_entry *tmp = RBH_ROOT(rbt), *best = NULL;
+ const struct rb_entry *tmp = RBH_ROOT(rbt), *best = NULL;
int comp;
while (tmp != NULL) {
@@ -443,8 +444,10 @@ struct rb_entry *typed_rb_find_lt(struct rbt_tree *rbt,
return best;
}
-struct rb_entry *typed_rb_next(struct rb_entry *rbe)
+struct rb_entry *typed_rb_next(const struct rb_entry *rbe_const)
{
+ struct rb_entry *rbe = (struct rb_entry *)rbe_const;
+
if (RBE_RIGHT(rbe) != NULL) {
rbe = RBE_RIGHT(rbe);
while (RBE_LEFT(rbe) != NULL)
@@ -463,7 +466,7 @@ struct rb_entry *typed_rb_next(struct rb_entry *rbe)
return rbe;
}
-struct rb_entry *typed_rb_min(struct rbt_tree *rbt)
+struct rb_entry *typed_rb_min(const struct rbt_tree *rbt)
{
struct rb_entry *rbe = RBH_ROOT(rbt);
struct rb_entry *parent = NULL;
diff --git a/lib/typerb.h b/lib/typerb.h
index 2d7b0ba637..fca45e20d1 100644
--- a/lib/typerb.h
+++ b/lib/typerb.h
@@ -45,23 +45,23 @@ struct typed_rb_entry *typed_rb_insert(struct typed_rb_root *rbt,
const struct typed_rb_entry *b));
struct typed_rb_entry *typed_rb_remove(struct typed_rb_root *rbt,
struct typed_rb_entry *rbe);
-struct typed_rb_entry *typed_rb_find(struct typed_rb_root *rbt,
+const struct typed_rb_entry *typed_rb_find(const struct typed_rb_root *rbt,
const struct typed_rb_entry *rbe,
int (*cmpfn)(
const struct typed_rb_entry *a,
const struct typed_rb_entry *b));
-struct typed_rb_entry *typed_rb_find_gteq(struct typed_rb_root *rbt,
+const struct typed_rb_entry *typed_rb_find_gteq(const struct typed_rb_root *rbt,
const struct typed_rb_entry *rbe,
int (*cmpfn)(
const struct typed_rb_entry *a,
const struct typed_rb_entry *b));
-struct typed_rb_entry *typed_rb_find_lt(struct typed_rb_root *rbt,
+const struct typed_rb_entry *typed_rb_find_lt(const struct typed_rb_root *rbt,
const struct typed_rb_entry *rbe,
int (*cmpfn)(
const struct typed_rb_entry *a,
const struct typed_rb_entry *b));
-struct typed_rb_entry *typed_rb_min(struct typed_rb_root *rbt);
-struct typed_rb_entry *typed_rb_next(struct typed_rb_entry *rbe);
+struct typed_rb_entry *typed_rb_min(const struct typed_rb_root *rbt);
+struct typed_rb_entry *typed_rb_next(const struct typed_rb_entry *rbe);
#define _PREDECL_RBTREE(prefix) \
struct prefix ## _head { struct typed_rb_root rr; }; \
@@ -86,20 +86,21 @@ macro_inline type *prefix ## _add(struct prefix##_head *h, type *item) \
re = typed_rb_insert(&h->rr, &item->field.re, cmpfn_uq); \
return container_of_null(re, type, field.re); \
} \
-macro_inline type *prefix ## _find_gteq(struct prefix##_head *h, \
- const type *item) \
+macro_inline const type *prefix ## _const_find_gteq( \
+ const struct prefix##_head *h, const type *item) \
{ \
- struct typed_rb_entry *re; \
+ const struct typed_rb_entry *re; \
re = typed_rb_find_gteq(&h->rr, &item->field.re, cmpfn_nuq); \
return container_of_null(re, type, field.re); \
} \
-macro_inline type *prefix ## _find_lt(struct prefix##_head *h, \
- const type *item) \
+macro_inline const type *prefix ## _const_find_lt( \
+ const struct prefix##_head *h, const type *item) \
{ \
- struct typed_rb_entry *re; \
+ const struct typed_rb_entry *re; \
re = typed_rb_find_lt(&h->rr, &item->field.re, cmpfn_nuq); \
return container_of_null(re, type, field.re); \
} \
+TYPESAFE_FIND_CMP(prefix, type) \
macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \
{ \
struct typed_rb_entry *re; \
@@ -115,18 +116,20 @@ macro_inline type *prefix ## _pop(struct prefix##_head *h) \
typed_rb_remove(&h->rr, re); \
return container_of(re, type, field.re); \
} \
-macro_pure type *prefix ## _first(struct prefix##_head *h) \
+macro_pure const type *prefix ## _const_first(const struct prefix##_head *h) \
{ \
- struct typed_rb_entry *re; \
+ const struct typed_rb_entry *re; \
re = typed_rb_min(&h->rr); \
return container_of_null(re, type, field.re); \
} \
-macro_pure type *prefix ## _next(struct prefix##_head *h, type *item) \
+macro_pure const type *prefix ## _const_next(const struct prefix##_head *h, \
+ const type *item) \
{ \
- struct typed_rb_entry *re; \
+ const struct typed_rb_entry *re; \
re = typed_rb_next(&item->field.re); \
return container_of_null(re, type, field.re); \
} \
+TYPESAFE_FIRST_NEXT(prefix, type) \
macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
{ \
struct typed_rb_entry *re; \
@@ -149,12 +152,14 @@ macro_inline int prefix ## __cmp(const struct typed_rb_entry *a, \
return cmpfn(container_of(a, type, field.re), \
container_of(b, type, field.re)); \
} \
-macro_inline type *prefix ## _find(struct prefix##_head *h, const type *item) \
+macro_inline const type *prefix ## _const_find(const struct prefix##_head *h, \
+ const type *item) \
{ \
- struct typed_rb_entry *re; \
+ const struct typed_rb_entry *re; \
re = typed_rb_find(&h->rr, &item->field.re, &prefix ## __cmp); \
return container_of_null(re, type, field.re); \
} \
+TYPESAFE_FIND(prefix, type) \
\
_DECLARE_RBTREE(prefix, type, field, prefix ## __cmp, prefix ## __cmp) \
/* ... */
diff --git a/lib/typesafe.c b/lib/typesafe.c
index a52b55b734..69796e2d81 100644
--- a/lib/typesafe.c
+++ b/lib/typesafe.c
@@ -158,7 +158,7 @@ void typesafe_hash_shrink(struct thash_head *head)
/* skiplist */
-static inline struct sskip_item *sl_level_get(struct sskip_item *item,
+static inline struct sskip_item *sl_level_get(const struct sskip_item *item,
size_t level)
{
if (level < SKIPLIST_OVERFLOW)
@@ -263,13 +263,14 @@ struct sskip_item *typesafe_skiplist_add(struct sskip_head *head,
/* NOTE: level counting below is 1-based since that makes the code simpler! */
-struct sskip_item *typesafe_skiplist_find(struct sskip_head *head,
+const struct sskip_item *typesafe_skiplist_find(
+ const struct sskip_head *head,
const struct sskip_item *item, int (*cmpfn)(
const struct sskip_item *a,
const struct sskip_item *b))
{
size_t level = SKIPLIST_MAXDEPTH;
- struct sskip_item *prev = &head->hitem, *next;
+ const struct sskip_item *prev = &head->hitem, *next;
int cmpval;
while (level) {
@@ -290,13 +291,14 @@ struct sskip_item *typesafe_skiplist_find(struct sskip_head *head,
return NULL;
}
-struct sskip_item *typesafe_skiplist_find_gteq(struct sskip_head *head,
+const struct sskip_item *typesafe_skiplist_find_gteq(
+ const struct sskip_head *head,
const struct sskip_item *item, int (*cmpfn)(
const struct sskip_item *a,
const struct sskip_item *b))
{
size_t level = SKIPLIST_MAXDEPTH;
- struct sskip_item *prev = &head->hitem, *next;
+ const struct sskip_item *prev = &head->hitem, *next;
int cmpval;
while (level) {
@@ -317,13 +319,14 @@ struct sskip_item *typesafe_skiplist_find_gteq(struct sskip_head *head,
return next;
}
-struct sskip_item *typesafe_skiplist_find_lt(struct sskip_head *head,
+const struct sskip_item *typesafe_skiplist_find_lt(
+ const struct sskip_head *head,
const struct sskip_item *item, int (*cmpfn)(
const struct sskip_item *a,
const struct sskip_item *b))
{
size_t level = SKIPLIST_MAXDEPTH;
- struct sskip_item *prev = &head->hitem, *next, *best = NULL;
+ const struct sskip_item *prev = &head->hitem, *next, *best = NULL;
int cmpval;
while (level) {
diff --git a/lib/typesafe.h b/lib/typesafe.h
index c30d73d1b3..e134316dd9 100644
--- a/lib/typesafe.h
+++ b/lib/typesafe.h
@@ -44,6 +44,41 @@ extern "C" {
item; \
item = from, from = prefix##_next_safe(head, from))
+
+/* non-const variants. these wrappers are the same for all the types, so
+ * bundle them together here.
+ */
+#define TYPESAFE_FIRST_NEXT(prefix, type) \
+macro_pure type *prefix ## _first(struct prefix##_head *h) \
+{ \
+ return (type *)prefix ## _const_first(h); \
+} \
+macro_pure type *prefix ## _next(struct prefix##_head *h, type *item) \
+{ \
+ return (type *)prefix ## _const_next(h, item); \
+} \
+/* ... */
+#define TYPESAFE_FIND(prefix, type) \
+macro_inline type *prefix ## _find(struct prefix##_head *h, \
+ const type *item) \
+{ \
+ return (type *)prefix ## _const_find(h, item); \
+} \
+/* ... */
+#define TYPESAFE_FIND_CMP(prefix, type) \
+macro_inline type *prefix ## _find_lt(struct prefix##_head *h, \
+ const type *item) \
+{ \
+ return (type *)prefix ## _const_find_lt(h, item); \
+} \
+macro_inline type *prefix ## _find_gteq(struct prefix##_head *h, \
+ const type *item) \
+{ \
+ return (type *)prefix ## _const_find_gteq(h, item); \
+} \
+/* ... */
+
+
/* single-linked list, unsorted/arbitrary.
* can be used as queue with add_tail / pop
*/
@@ -133,15 +168,17 @@ macro_inline type *prefix ## _pop(struct prefix##_head *h) \
h->sh.last_next = &h->sh.first; \
return container_of(sitem, type, field.si); \
} \
-macro_pure type *prefix ## _first(struct prefix##_head *h) \
+macro_pure const type *prefix ## _const_first(const struct prefix##_head *h) \
{ \
return container_of_null(h->sh.first, type, field.si); \
} \
-macro_pure type *prefix ## _next(struct prefix##_head * h, type *item) \
+macro_pure const type *prefix ## _const_next(const struct prefix##_head *h, \
+ const type *item) \
{ \
- struct slist_item *sitem = &item->field.si; \
+ const struct slist_item *sitem = &item->field.si; \
return container_of_null(sitem->next, type, field.si); \
} \
+TYPESAFE_FIRST_NEXT(prefix, type) \
macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
{ \
struct slist_item *sitem; \
@@ -232,20 +269,22 @@ macro_inline type *prefix ## _pop(struct prefix##_head *h) \
h->dh.count--; \
return container_of(ditem, type, field.di); \
} \
-macro_pure type *prefix ## _first(struct prefix##_head *h) \
+macro_pure const type *prefix ## _const_first(const struct prefix##_head *h) \
{ \
- struct dlist_item *ditem = h->dh.hitem.next; \
+ const struct dlist_item *ditem = h->dh.hitem.next; \
if (ditem == &h->dh.hitem) \
return NULL; \
return container_of(ditem, type, field.di); \
} \
-macro_pure type *prefix ## _next(struct prefix##_head * h, type *item) \
+macro_pure const type *prefix ## _const_next(const struct prefix##_head *h, \
+ const type *item) \
{ \
- struct dlist_item *ditem = &item->field.di; \
+ const struct dlist_item *ditem = &item->field.di; \
if (ditem->next == &h->dh.hitem) \
return NULL; \
return container_of(ditem->next, type, field.di); \
} \
+TYPESAFE_FIRST_NEXT(prefix, type) \
macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
{ \
if (!item) \
@@ -338,19 +377,21 @@ macro_inline type *prefix ## _pop(struct prefix##_head *h) \
typesafe_heap_resize(&h->hh, false); \
return container_of(hitem, type, field.hi); \
} \
-macro_pure type *prefix ## _first(struct prefix##_head *h) \
+macro_pure const type *prefix ## _const_first(const struct prefix##_head *h) \
{ \
if (h->hh.count == 0) \
return NULL; \
return container_of(h->hh.array[0], type, field.hi); \
} \
-macro_pure type *prefix ## _next(struct prefix##_head *h, type *item) \
+macro_pure const type *prefix ## _const_next(const struct prefix##_head *h, \
+ const type *item) \
{ \
uint32_t idx = item->field.hi.index + 1; \
if (idx >= h->hh.count) \
return NULL; \
return container_of(h->hh.array[idx], type, field.hi); \
} \
+TYPESAFE_FIRST_NEXT(prefix, type) \
macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
{ \
if (!item) \
@@ -431,26 +472,27 @@ macro_inline type *prefix ## _add(struct prefix##_head *h, type *item) \
h->sh.count++; \
return NULL; \
} \
-macro_inline type *prefix ## _find_gteq(struct prefix##_head *h, \
- const type *item) \
+macro_inline const type *prefix ## _const_find_gteq( \
+ const struct prefix##_head *h, const type *item) \
{ \
- struct ssort_item *sitem = h->sh.first; \
+ const struct ssort_item *sitem = h->sh.first; \
int cmpval = 0; \
while (sitem && (cmpval = cmpfn_nuq( \
container_of(sitem, type, field.si), item)) < 0) \
sitem = sitem->next; \
return container_of_null(sitem, type, field.si); \
} \
-macro_inline type *prefix ## _find_lt(struct prefix##_head *h, \
- const type *item) \
+macro_inline const type *prefix ## _const_find_lt( \
+ const struct prefix##_head *h, const type *item) \
{ \
- struct ssort_item *prev = NULL, *sitem = h->sh.first; \
+ const struct ssort_item *prev = NULL, *sitem = h->sh.first; \
int cmpval = 0; \
while (sitem && (cmpval = cmpfn_nuq( \
container_of(sitem, type, field.si), item)) < 0) \
sitem = (prev = sitem)->next; \
return container_of_null(prev, type, field.si); \
} \
+TYPESAFE_FIND_CMP(prefix, type) \
/* TODO: del_hint */ \
macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \
{ \
@@ -472,15 +514,17 @@ macro_inline type *prefix ## _pop(struct prefix##_head *h) \
h->sh.first = sitem->next; \
return container_of(sitem, type, field.si); \
} \
-macro_pure type *prefix ## _first(struct prefix##_head *h) \
+macro_pure const type *prefix ## _const_first(const struct prefix##_head *h) \
{ \
return container_of_null(h->sh.first, type, field.si); \
} \
-macro_pure type *prefix ## _next(struct prefix##_head *h, type *item) \
+macro_pure const type *prefix ## _const_next(const struct prefix##_head *h, \
+ const type *item) \
{ \
- struct ssort_item *sitem = &item->field.si; \
+ const struct ssort_item *sitem = &item->field.si; \
return container_of_null(sitem->next, type, field.si); \
} \
+TYPESAFE_FIRST_NEXT(prefix, type) \
macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
{ \
struct ssort_item *sitem; \
@@ -497,10 +541,11 @@ macro_pure size_t prefix ## _count(const struct prefix##_head *h) \
#define DECLARE_SORTLIST_UNIQ(prefix, type, field, cmpfn) \
_DECLARE_SORTLIST(prefix, type, field, cmpfn, cmpfn) \
- \
-macro_inline type *prefix ## _find(struct prefix##_head *h, const type *item) \
+ \
+macro_inline const type *prefix ## _const_find(const struct prefix##_head *h, \
+ const type *item) \
{ \
- struct ssort_item *sitem = h->sh.first; \
+ const struct ssort_item *sitem = h->sh.first; \
int cmpval = 0; \
while (sitem && (cmpval = cmpfn( \
container_of(sitem, type, field.si), item)) < 0) \
@@ -509,6 +554,7 @@ macro_inline type *prefix ## _find(struct prefix##_head *h, const type *item) \
return NULL; \
return container_of(sitem, type, field.si); \
} \
+TYPESAFE_FIND(prefix, type) \
/* ... */
#define DECLARE_SORTLIST_NONUNIQ(prefix, type, field, cmpfn) \
@@ -606,12 +652,13 @@ macro_inline type *prefix ## _add(struct prefix##_head *h, type *item) \
*np = &item->field.hi; \
return NULL; \
} \
-macro_inline type *prefix ## _find(struct prefix##_head *h, const type *item) \
+macro_inline const type *prefix ## _const_find(const struct prefix##_head *h, \
+ const type *item) \
{ \
if (!h->hh.tabshift) \
return NULL; \
uint32_t hval = hashfn(item), hbits = HASH_KEY(h->hh, hval); \
- struct thash_item *hitem = h->hh.entries[hbits]; \
+ const struct thash_item *hitem = h->hh.entries[hbits]; \
while (hitem && hitem->hashval < hval) \
hitem = hitem->next; \
while (hitem && hitem->hashval == hval) { \
@@ -621,6 +668,7 @@ macro_inline type *prefix ## _find(struct prefix##_head *h, const type *item) \
} \
return NULL; \
} \
+TYPESAFE_FIND(prefix, type) \
macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \
{ \
if (!h->hh.tabshift) \
@@ -655,7 +703,7 @@ macro_inline type *prefix ## _pop(struct prefix##_head *h) \
} \
return NULL; \
} \
-macro_pure type *prefix ## _first(struct prefix##_head *h) \
+macro_pure const type *prefix ## _const_first(const struct prefix##_head *h) \
{ \
uint32_t i; \
for (i = 0; i < HASH_SIZE(h->hh); i++) \
@@ -663,17 +711,19 @@ macro_pure type *prefix ## _first(struct prefix##_head *h) \
return container_of(h->hh.entries[i], type, field.hi); \
return NULL; \
} \
-macro_pure type *prefix ## _next(struct prefix##_head *h, type *item) \
+macro_pure const type *prefix ## _const_next(const struct prefix##_head *h, \
+ const type *item) \
{ \
- struct thash_item *hitem = &item->field.hi; \
+ const struct thash_item *hitem = &item->field.hi; \
if (hitem->next) \
return container_of(hitem->next, type, field.hi); \
uint32_t i = HASH_KEY(h->hh, hitem->hashval) + 1; \
- for (; i < HASH_SIZE(h->hh); i++) \
+ for (; i < HASH_SIZE(h->hh); i++) \
if (h->hh.entries[i]) \
return container_of(h->hh.entries[i], type, field.hi); \
return NULL; \
} \
+TYPESAFE_FIRST_NEXT(prefix, type) \
macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
{ \
if (!item) \
@@ -742,20 +792,21 @@ macro_inline type *prefix ## _add(struct prefix##_head *h, type *item) \
si = typesafe_skiplist_add(&h->sh, &item->field.si, cmpfn_uq); \
return container_of_null(si, type, field.si); \
} \
-macro_inline type *prefix ## _find_gteq(struct prefix##_head *h, \
- const type *item) \
+macro_inline const type *prefix ## _const_find_gteq( \
+ const struct prefix##_head *h, const type *item) \
{ \
- struct sskip_item *sitem = typesafe_skiplist_find_gteq(&h->sh, \
+ const struct sskip_item *sitem = typesafe_skiplist_find_gteq(&h->sh, \
&item->field.si, cmpfn_nuq); \
return container_of_null(sitem, type, field.si); \
} \
-macro_inline type *prefix ## _find_lt(struct prefix##_head *h, \
- const type *item) \
+macro_inline const type *prefix ## _const_find_lt( \
+ const struct prefix##_head *h, const type *item) \
{ \
- struct sskip_item *sitem = typesafe_skiplist_find_lt(&h->sh, \
+ const struct sskip_item *sitem = typesafe_skiplist_find_lt(&h->sh, \
&item->field.si, cmpfn_nuq); \
return container_of_null(sitem, type, field.si); \
} \
+TYPESAFE_FIND_CMP(prefix, type) \
macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \
{ \
struct sskip_item *sitem = typesafe_skiplist_del(&h->sh, \
@@ -767,16 +818,18 @@ macro_inline type *prefix ## _pop(struct prefix##_head *h) \
struct sskip_item *sitem = typesafe_skiplist_pop(&h->sh); \
return container_of_null(sitem, type, field.si); \
} \
-macro_pure type *prefix ## _first(struct prefix##_head *h) \
+macro_pure const type *prefix ## _const_first(const struct prefix##_head *h) \
{ \
- struct sskip_item *first = h->sh.hitem.next[0]; \
+ const struct sskip_item *first = h->sh.hitem.next[0]; \
return container_of_null(first, type, field.si); \
} \
-macro_pure type *prefix ## _next(struct prefix##_head *h, type *item) \
+macro_pure const type *prefix ## _const_next(const struct prefix##_head *h, \
+ const type *item) \
{ \
- struct sskip_item *next = item->field.si.next[0]; \
+ const struct sskip_item *next = item->field.si.next[0]; \
return container_of_null(next, type, field.si); \
} \
+TYPESAFE_FIRST_NEXT(prefix, type) \
macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \
{ \
struct sskip_item *next; \
@@ -792,19 +845,21 @@ macro_pure size_t prefix ## _count(const struct prefix##_head *h) \
#define PREDECL_SKIPLIST_UNIQ(prefix) \
_PREDECL_SKIPLIST(prefix)
#define DECLARE_SKIPLIST_UNIQ(prefix, type, field, cmpfn) \
- \
+ \
macro_inline int prefix ## __cmp(const struct sskip_item *a, \
const struct sskip_item *b) \
{ \
return cmpfn(container_of(a, type, field.si), \
container_of(b, type, field.si)); \
} \
-macro_inline type *prefix ## _find(struct prefix##_head *h, const type *item) \
+macro_inline const type *prefix ## _const_find(const struct prefix##_head *h, \
+ const type *item) \
{ \
- struct sskip_item *sitem = typesafe_skiplist_find(&h->sh, \
+ const struct sskip_item *sitem = typesafe_skiplist_find(&h->sh, \
&item->field.si, &prefix ## __cmp); \
return container_of_null(sitem, type, field.si); \
} \
+TYPESAFE_FIND(prefix, type) \
\
_DECLARE_SKIPLIST(prefix, type, field, \
prefix ## __cmp, prefix ## __cmp) \
@@ -843,15 +898,18 @@ extern struct sskip_item *typesafe_skiplist_add(struct sskip_head *head,
struct sskip_item *item, int (*cmpfn)(
const struct sskip_item *a,
const struct sskip_item *b));
-extern struct sskip_item *typesafe_skiplist_find(struct sskip_head *head,
+extern const struct sskip_item *typesafe_skiplist_find(
+ const struct sskip_head *head,
const struct sskip_item *item, int (*cmpfn)(
const struct sskip_item *a,
const struct sskip_item *b));
-extern struct sskip_item *typesafe_skiplist_find_gteq(struct sskip_head *head,
+extern const struct sskip_item *typesafe_skiplist_find_gteq(
+ const struct sskip_head *head,
const struct sskip_item *item, int (*cmpfn)(
const struct sskip_item *a,
const struct sskip_item *b));
-extern struct sskip_item *typesafe_skiplist_find_lt(struct sskip_head *head,
+extern const struct sskip_item *typesafe_skiplist_find_lt(
+ const struct sskip_head *head,
const struct sskip_item *item, int (*cmpfn)(
const struct sskip_item *a,
const struct sskip_item *b));
diff --git a/lib/vrf.c b/lib/vrf.c
index 6bd577fce1..9df5d19516 100644
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -652,7 +652,8 @@ int vrf_handler_create(struct vty *vty, const char *vrfname,
}
int vrf_netns_handler_create(struct vty *vty, struct vrf *vrf, char *pathname,
- ns_id_t ns_id, ns_id_t internal_ns_id)
+ ns_id_t ns_id, ns_id_t internal_ns_id,
+ ns_id_t rel_def_ns_id)
{
struct ns *ns = NULL;
@@ -700,6 +701,7 @@ int vrf_netns_handler_create(struct vty *vty, struct vrf *vrf, char *pathname,
}
ns = ns_get_created(ns, pathname, ns_id);
ns->internal_ns_id = internal_ns_id;
+ ns->relative_default_ns = rel_def_ns_id;
ns->vrf_ctxt = (void *)vrf;
vrf->ns_ctxt = (void *)ns;
/* update VRF netns NAME */
@@ -797,7 +799,9 @@ DEFUN_NOSH (vrf_netns,
frr_with_privs(vrf_daemon_privs) {
ret = vrf_netns_handler_create(vty, vrf, pathname,
- NS_UNKNOWN, NS_UNKNOWN);
+ NS_UNKNOWN,
+ NS_UNKNOWN,
+ NS_UNKNOWN);
}
return ret;
}
diff --git a/lib/vrf.h b/lib/vrf.h
index 83ed16b48e..a8514d74ed 100644
--- a/lib/vrf.h
+++ b/lib/vrf.h
@@ -315,7 +315,7 @@ extern int vrf_handler_create(struct vty *vty, const char *name,
*/
extern int vrf_netns_handler_create(struct vty *vty, struct vrf *vrf,
char *pathname, ns_id_t ext_ns_id,
- ns_id_t ns_id);
+ ns_id_t ns_id, ns_id_t rel_def_ns_id);
/* used internally to enable or disable VRF.
* Notify a change in the VRF ID of the VRF
diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c
index 6e71a21bd5..cea4dd93e5 100644
--- a/ospf6d/ospf6_asbr.c
+++ b/ospf6d/ospf6_asbr.c
@@ -47,6 +47,9 @@
#include "ospf6_flood.h"
#include "ospf6d.h"
+static void ospf6_asbr_redistribute_set(int type);
+static void ospf6_asbr_redistribute_unset(int type);
+
unsigned char conf_debug_ospf6_asbr = 0;
#define ZROUTE_NAME(x) zebra_route_string(x)
@@ -935,18 +938,35 @@ static void ospf6_asbr_routemap_update(const char *mapname)
ospf6->rmap[type].map = route_map_lookup_by_name(
ospf6->rmap[type].name);
- if (mapname && ospf6->rmap[type].map
+ if (mapname
&& (strcmp(ospf6->rmap[type].name, mapname) == 0)) {
- if (IS_OSPF6_DEBUG_ASBR)
- zlog_debug(
- "%s: route-map %s update, reset redist %s",
- __func__, mapname,
- ZROUTE_NAME(type));
+ if (ospf6->rmap[type].map) {
+ if (IS_OSPF6_DEBUG_ASBR)
+ zlog_debug(
+ "%s: route-map %s update, reset redist %s",
+ __func__, mapname,
+ ZROUTE_NAME(type));
- route_map_counter_increment(
- ospf6->rmap[type].map);
+ route_map_counter_increment(
+ ospf6->rmap[type].map);
- ospf6_asbr_distribute_list_update(type);
+ ospf6_asbr_distribute_list_update(type);
+ } else {
+ /*
+ * if the mapname matches a route-map on
+ * ospf6 but the map doesn't exist, it
+ * is being deleted. flush and then
+ * readvertise
+ */
+ if (IS_OSPF6_DEBUG_ASBR)
+ zlog_debug(
+ "%s: route-map %s deleted, reset redist %s",
+ __func__, mapname,
+ ZROUTE_NAME(type));
+ ospf6_asbr_redistribute_unset(type);
+ ospf6_asbr_routemap_set(type, mapname);
+ ospf6_asbr_redistribute_set(type);
+ }
}
} else
ospf6->rmap[type].map = NULL;
@@ -1061,6 +1081,7 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex,
if (IS_OSPF6_DEBUG_ASBR)
zlog_debug("Denied by route-map \"%s\"",
ospf6->rmap[type].name);
+ ospf6_asbr_redistribute_remove(type, ifindex, prefix);
return;
}
}
diff --git a/ospf6d/ospf6_lsdb.c b/ospf6d/ospf6_lsdb.c
index 0a9f1c6f7c..b551dbdfa6 100644
--- a/ospf6d/ospf6_lsdb.c
+++ b/ospf6d/ospf6_lsdb.c
@@ -298,17 +298,13 @@ struct ospf6_lsa *ospf6_lsdb_next(const struct route_node *iterend,
void ospf6_lsdb_remove_all(struct ospf6_lsdb *lsdb)
{
- struct ospf6_lsa *lsa, *lsa_next;
- const struct route_node *iterend;
+ struct ospf6_lsa *lsa;
if (lsdb == NULL)
return;
- for (iterend = ospf6_lsdb_head(lsdb, 0, 0, 0, &lsa); lsa;
- lsa = lsa_next) {
- lsa_next = ospf6_lsdb_next(iterend, lsa);
+ for (ALL_LSDB(lsdb, lsa))
ospf6_lsdb_remove(lsa, lsdb);
- }
}
void ospf6_lsdb_lsa_unlock(struct ospf6_lsa *lsa)
@@ -323,12 +319,9 @@ void ospf6_lsdb_lsa_unlock(struct ospf6_lsa *lsa)
int ospf6_lsdb_maxage_remover(struct ospf6_lsdb *lsdb)
{
int reschedule = 0;
- struct ospf6_lsa *lsa, *lsa_next;
- const struct route_node *iterend;
+ struct ospf6_lsa *lsa;
- for (iterend = ospf6_lsdb_head(lsdb, 0, 0, 0, &lsa); lsa;
- lsa = lsa_next) {
- lsa_next = ospf6_lsdb_next(iterend, lsa);
+ for (ALL_LSDB(lsdb, lsa)) {
if (!OSPF6_LSA_IS_MAXAGE(lsa))
continue;
if (lsa->retrans_count != 0) {
diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c
index 31862a2298..f891f548ae 100644
--- a/ospf6d/ospf6_message.c
+++ b/ospf6d/ospf6_message.c
@@ -1859,8 +1859,7 @@ int ospf6_dbdesc_send(struct thread *thread)
int ospf6_dbdesc_send_newone(struct thread *thread)
{
struct ospf6_neighbor *on;
- struct ospf6_lsa *lsa, *lsa_next;
- const struct route_node *iterend;
+ struct ospf6_lsa *lsa;
unsigned int size = 0;
on = (struct ospf6_neighbor *)THREAD_ARG(thread);
@@ -1870,10 +1869,7 @@ int ospf6_dbdesc_send_newone(struct thread *thread)
structure)
so that ospf6_send_dbdesc () can send those LSAs */
size = sizeof(struct ospf6_lsa_header) + sizeof(struct ospf6_dbdesc);
-
- for (iterend = ospf6_lsdb_head(on->summary_list, 0, 0, 0, &lsa); lsa;
- lsa = lsa_next) {
- lsa_next = ospf6_lsdb_next(iterend, lsa);
+ for (ALL_LSDB(on->summary_list, lsa)) {
if (size + sizeof(struct ospf6_lsa_header)
> ospf6_packet_max(on->ospf6_if)) {
ospf6_lsdb_lsa_unlock(lsa);
@@ -2016,8 +2012,7 @@ int ospf6_lsupdate_send_neighbor(struct thread *thread)
struct ospf6_lsupdate *lsupdate;
uint8_t *p;
int lsa_cnt;
- struct ospf6_lsa *lsa, *lsa_next;
- const struct route_node *iterend;
+ struct ospf6_lsa *lsa;
on = (struct ospf6_neighbor *)THREAD_ARG(thread);
on->thread_send_lsupdate = (struct thread *)NULL;
@@ -2042,9 +2037,7 @@ int ospf6_lsupdate_send_neighbor(struct thread *thread)
/* lsupdate_list lists those LSA which doesn't need to be
retransmitted. remove those from the list */
- for (iterend = ospf6_lsdb_head(on->lsupdate_list, 0, 0, 0, &lsa); lsa;
- lsa = lsa_next) {
- lsa_next = ospf6_lsdb_next(iterend, lsa);
+ for (ALL_LSDB(on->lsupdate_list, lsa)) {
/* MTU check */
if ((p - sendbuf + (unsigned int)OSPF6_LSA_SIZE(lsa->header))
> ospf6_packet_max(on->ospf6_if)) {
@@ -2074,7 +2067,7 @@ int ospf6_lsupdate_send_neighbor(struct thread *thread)
p += OSPF6_LSA_SIZE(lsa->header);
lsa_cnt++;
- assert(lsa->lock == 1);
+ assert(lsa->lock == 2);
ospf6_lsdb_remove(lsa, on->lsupdate_list);
}
@@ -2201,8 +2194,7 @@ int ospf6_lsupdate_send_interface(struct thread *thread)
struct ospf6_lsupdate *lsupdate;
uint8_t *p;
int lsa_cnt;
- struct ospf6_lsa *lsa, *lsa_next;
- const struct route_node *iterend;
+ struct ospf6_lsa *lsa;
oi = (struct ospf6_interface *)THREAD_ARG(thread);
oi->thread_send_lsupdate = (struct thread *)NULL;
@@ -2228,9 +2220,7 @@ int ospf6_lsupdate_send_interface(struct thread *thread)
p = (uint8_t *)((caddr_t)lsupdate + sizeof(struct ospf6_lsupdate));
lsa_cnt = 0;
- for (iterend = ospf6_lsdb_head(oi->lsupdate_list, 0, 0, 0, &lsa); lsa;
- lsa = lsa_next) {
- lsa_next = ospf6_lsdb_next(iterend, lsa);
+ for (ALL_LSDB(oi->lsupdate_list, lsa)) {
/* MTU check */
if ((p - sendbuf + ((unsigned int)OSPF6_LSA_SIZE(lsa->header)))
> ospf6_packet_max(oi)) {
@@ -2264,7 +2254,7 @@ int ospf6_lsupdate_send_interface(struct thread *thread)
p += OSPF6_LSA_SIZE(lsa->header);
lsa_cnt++;
- assert(lsa->lock == 1);
+ assert(lsa->lock == 2);
ospf6_lsdb_remove(lsa, oi->lsupdate_list);
}
@@ -2290,8 +2280,7 @@ int ospf6_lsack_send_neighbor(struct thread *thread)
struct ospf6_neighbor *on;
struct ospf6_header *oh;
uint8_t *p;
- struct ospf6_lsa *lsa, *lsa_next;
- const struct route_node *iterend;
+ struct ospf6_lsa *lsa;
int lsa_cnt = 0;
on = (struct ospf6_neighbor *)THREAD_ARG(thread);
@@ -2314,9 +2303,7 @@ int ospf6_lsack_send_neighbor(struct thread *thread)
p = (uint8_t *)((caddr_t)oh + sizeof(struct ospf6_header));
- for (iterend = ospf6_lsdb_head(on->lsack_list, 0, 0, 0, &lsa); lsa;
- lsa = lsa_next) {
- lsa_next = ospf6_lsdb_next(iterend, lsa);
+ for (ALL_LSDB(on->lsack_list, lsa)) {
/* MTU check */
if (p - sendbuf + sizeof(struct ospf6_lsa_header)
> ospf6_packet_max(on->ospf6_if)) {
@@ -2344,7 +2331,7 @@ int ospf6_lsack_send_neighbor(struct thread *thread)
memcpy(p, lsa->header, sizeof(struct ospf6_lsa_header));
p += sizeof(struct ospf6_lsa_header);
- assert(lsa->lock == 1);
+ assert(lsa->lock == 2);
ospf6_lsdb_remove(lsa, on->lsack_list);
lsa_cnt++;
}
@@ -2371,8 +2358,7 @@ int ospf6_lsack_send_interface(struct thread *thread)
struct ospf6_interface *oi;
struct ospf6_header *oh;
uint8_t *p;
- struct ospf6_lsa *lsa, *lsa_next;
- const struct route_node *iterend;
+ struct ospf6_lsa *lsa;
int lsa_cnt = 0;
oi = (struct ospf6_interface *)THREAD_ARG(thread);
@@ -2396,9 +2382,7 @@ int ospf6_lsack_send_interface(struct thread *thread)
p = (uint8_t *)((caddr_t)oh + sizeof(struct ospf6_header));
- for (iterend = ospf6_lsdb_head(oi->lsack_list, 0, 0, 0, &lsa); lsa;
- lsa = lsa_next) {
- lsa_next = ospf6_lsdb_next(iterend, lsa);
+ for (ALL_LSDB(oi->lsack_list, lsa)) {
/* MTU check */
if (p - sendbuf + sizeof(struct ospf6_lsa_header)
> ospf6_packet_max(oi)) {
@@ -2416,7 +2400,7 @@ int ospf6_lsack_send_interface(struct thread *thread)
memcpy(p, lsa->header, sizeof(struct ospf6_lsa_header));
p += sizeof(struct ospf6_lsa_header);
- assert(lsa->lock == 1);
+ assert(lsa->lock == 2);
ospf6_lsdb_remove(lsa, oi->lsack_list);
lsa_cnt++;
}
diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c
index 1e90d4b9b5..92a3c9e1ad 100644
--- a/ospf6d/ospf6_neighbor.c
+++ b/ospf6d/ospf6_neighbor.c
@@ -118,15 +118,11 @@ struct ospf6_neighbor *ospf6_neighbor_create(uint32_t router_id,
void ospf6_neighbor_delete(struct ospf6_neighbor *on)
{
- struct ospf6_lsa *lsa, *lsa_next;
- const struct route_node *iterend;
+ struct ospf6_lsa *lsa;
ospf6_lsdb_remove_all(on->summary_list);
ospf6_lsdb_remove_all(on->request_list);
-
- for (iterend = ospf6_lsdb_head(on->retrans_list, 0, 0, 0, &lsa); lsa;
- lsa = lsa_next) {
- lsa_next = ospf6_lsdb_next(iterend, lsa);
+ for (ALL_LSDB(on->retrans_list, lsa)) {
ospf6_decrement_retrans_count(lsa);
ospf6_lsdb_remove(lsa, on->retrans_list);
}
@@ -297,8 +293,7 @@ int twoway_received(struct thread *thread)
int negotiation_done(struct thread *thread)
{
struct ospf6_neighbor *on;
- struct ospf6_lsa *lsa, *lsa_next;
- const struct route_node *iterend;
+ struct ospf6_lsa *lsa;
on = (struct ospf6_neighbor *)THREAD_ARG(thread);
assert(on);
@@ -312,10 +307,7 @@ int negotiation_done(struct thread *thread)
/* clear ls-list */
ospf6_lsdb_remove_all(on->summary_list);
ospf6_lsdb_remove_all(on->request_list);
-
- for (iterend = ospf6_lsdb_head(on->retrans_list, 0, 0, 0, &lsa); lsa;
- lsa = lsa_next) {
- lsa_next = ospf6_lsdb_next(iterend, lsa);
+ for (ALL_LSDB(on->retrans_list, lsa)) {
ospf6_decrement_retrans_count(lsa);
ospf6_lsdb_remove(lsa, on->retrans_list);
}
@@ -509,8 +501,7 @@ int seqnumber_mismatch(struct thread *thread)
int bad_lsreq(struct thread *thread)
{
struct ospf6_neighbor *on;
- struct ospf6_lsa *lsa, *lsa_next;
- const struct route_node *iterend;
+ struct ospf6_lsa *lsa;
on = (struct ospf6_neighbor *)THREAD_ARG(thread);
assert(on);
@@ -529,10 +520,7 @@ int bad_lsreq(struct thread *thread)
ospf6_lsdb_remove_all(on->summary_list);
ospf6_lsdb_remove_all(on->request_list);
-
- for (iterend = ospf6_lsdb_head(on->retrans_list, 0, 0, 0, &lsa); lsa;
- lsa = lsa_next) {
- lsa_next = ospf6_lsdb_next(iterend, lsa);
+ for (ALL_LSDB(on->retrans_list, lsa)) {
ospf6_decrement_retrans_count(lsa);
ospf6_lsdb_remove(lsa, on->retrans_list);
}
@@ -550,8 +538,7 @@ int bad_lsreq(struct thread *thread)
int oneway_received(struct thread *thread)
{
struct ospf6_neighbor *on;
- struct ospf6_lsa *lsa, *lsa_next;
- const struct route_node *iterend;
+ struct ospf6_lsa *lsa;
on = (struct ospf6_neighbor *)THREAD_ARG(thread);
assert(on);
@@ -568,9 +555,7 @@ int oneway_received(struct thread *thread)
ospf6_lsdb_remove_all(on->summary_list);
ospf6_lsdb_remove_all(on->request_list);
- for (iterend = ospf6_lsdb_head(on->retrans_list, 0, 0, 0, &lsa); lsa;
- lsa = lsa_next) {
- lsa_next = ospf6_lsdb_next(iterend, lsa);
+ for (ALL_LSDB(on->retrans_list, lsa)) {
ospf6_decrement_retrans_count(lsa);
ospf6_lsdb_remove(lsa, on->retrans_list);
}
diff --git a/ospfd/ospf_asbr.c b/ospfd/ospf_asbr.c
index 6d00935347..3682b4cdd3 100644
--- a/ospfd/ospf_asbr.c
+++ b/ospfd/ospf_asbr.c
@@ -149,6 +149,7 @@ ospf_external_info_add(struct ospf *ospf, uint8_t type, unsigned short instance,
new->ifindex = ifindex;
new->nexthop = nexthop;
new->tag = tag;
+ new->orig_tag = tag;
/* we don't unlock rn from the get() because we're attaching the info */
if (rn)
diff --git a/ospfd/ospf_asbr.h b/ospfd/ospf_asbr.h
index ac7bd68b5f..1bcc32e3d8 100644
--- a/ospfd/ospf_asbr.h
+++ b/ospfd/ospf_asbr.h
@@ -46,6 +46,9 @@ struct external_info {
/* Additional Route tag. */
route_tag_t tag;
+ /* Actual tag received from zebra*/
+ route_tag_t orig_tag;
+
struct route_map_set_values route_map_set;
#define ROUTEMAP_METRIC(E) (E)->route_map_set.metric
#define ROUTEMAP_METRIC_TYPE(E) (E)->route_map_set.metric_type
diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
index 71275e49d2..4093837ba7 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -7809,7 +7809,7 @@ DEFUN_HIDDEN (no_ospf_priority,
DEFUN (ip_ospf_retransmit_interval,
ip_ospf_retransmit_interval_addr_cmd,
- "ip ospf retransmit-interval (3-65535) [A.B.C.D]",
+ "ip ospf retransmit-interval (1-65535) [A.B.C.D]",
"IP Information\n"
"OSPF interface commands\n"
"Time between retransmitting lost link state advertisements\n"
@@ -7823,7 +7823,7 @@ DEFUN (ip_ospf_retransmit_interval,
struct ospf_if_params *params;
params = IF_DEF_PARAMS(ifp);
- argv_find(argv, argc, "(3-65535)", &idx);
+ argv_find(argv, argc, "(1-65535)", &idx);
seconds = strtol(argv[idx]->arg, NULL, 10);
if (argv_find(argv, argc, "A.B.C.D", &idx)) {
@@ -7845,7 +7845,7 @@ DEFUN (ip_ospf_retransmit_interval,
DEFUN_HIDDEN (ospf_retransmit_interval,
ospf_retransmit_interval_cmd,
- "ospf retransmit-interval (3-65535) [A.B.C.D]",
+ "ospf retransmit-interval (1-65535) [A.B.C.D]",
"OSPF interface commands\n"
"Time between retransmitting lost link state advertisements\n"
"Seconds\n"
@@ -7856,7 +7856,7 @@ DEFUN_HIDDEN (ospf_retransmit_interval,
DEFUN (no_ip_ospf_retransmit_interval,
no_ip_ospf_retransmit_interval_addr_cmd,
- "no ip ospf retransmit-interval [(3-65535)] [A.B.C.D]",
+ "no ip ospf retransmit-interval [(1-65535)] [A.B.C.D]",
NO_STR
"IP Information\n"
"OSPF interface commands\n"
@@ -7896,7 +7896,7 @@ DEFUN (no_ip_ospf_retransmit_interval,
DEFUN_HIDDEN (no_ospf_retransmit_interval,
no_ospf_retransmit_interval_cmd,
- "no ospf retransmit-interval [(3-65535)] [A.B.C.D]",
+ "no ospf retransmit-interval [(1-65535)] [A.B.C.D]",
NO_STR
"OSPF interface commands\n"
"Time between retransmitting lost link state advertisements\n"
diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c
index c7e6bd9cbf..e8e2fbeaa6 100644
--- a/ospfd/ospf_zebra.c
+++ b/ospfd/ospf_zebra.c
@@ -696,6 +696,7 @@ int ospf_redistribute_check(struct ospf *ospf, struct external_info *ei,
struct ospf_redist *red;
uint8_t type = is_prefix_default(&ei->p) ? DEFAULT_ROUTE : ei->type;
unsigned short instance = is_prefix_default(&ei->p) ? 0 : ei->instance;
+ route_tag_t saved_tag = 0;
if (changed)
*changed = 0;
@@ -726,6 +727,10 @@ int ospf_redistribute_check(struct ospf *ospf, struct external_info *ei,
save_values = ei->route_map_set;
ospf_reset_route_map_set_values(&ei->route_map_set);
+ saved_tag = ei->tag;
+ /* Resetting with original route tag */
+ ei->tag = ei->orig_tag;
+
/* apply route-map if needed */
red = ospf_redist_lookup(ospf, type, instance);
if (red && ROUTEMAP_NAME(red)) {
@@ -747,9 +752,13 @@ int ospf_redistribute_check(struct ospf *ospf, struct external_info *ei,
}
/* check if 'route-map set' changed something */
- if (changed)
+ if (changed) {
*changed = !ospf_route_map_set_compare(
&ei->route_map_set, &save_values);
+
+ /* check if tag is modified */
+ *changed |= (saved_tag != ei->tag);
+ }
}
return 1;
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index 76ee18ee84..3ba02d628d 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -5662,14 +5662,20 @@ DEFUN (show_ip_pim_statistics,
return CMD_SUCCESS;
}
-static void show_multicast_interfaces(struct pim_instance *pim, struct vty *vty)
+static void show_multicast_interfaces(struct pim_instance *pim, struct vty *vty,
+ bool uj)
{
struct interface *ifp;
+ json_object *json = NULL;
+ json_object *json_row = NULL;
vty_out(vty, "\n");
- vty_out(vty,
- "Interface Address ifi Vif PktsIn PktsOut BytesIn BytesOut\n");
+ if (uj)
+ json = json_object_new_object();
+ else
+ vty_out(vty,
+ "Interface Address ifi Vif PktsIn PktsOut BytesIn BytesOut\n");
FOR_ALL_INTERFACES (pim->vrf, ifp) {
struct pim_interface *pim_ifp;
@@ -5693,12 +5699,43 @@ static void show_multicast_interfaces(struct pim_instance *pim, struct vty *vty)
}
ifaddr = pim_ifp->primary_address;
+ if (uj) {
+ json_row = json_object_new_object();
+ json_object_string_add(json_row, "name", ifp->name);
+ json_object_string_add(json_row, "state",
+ if_is_up(ifp) ? "up" : "down");
+ json_object_string_add(
+ json_row, "address",
+ inet_ntoa(pim_ifp->primary_address));
+ json_object_int_add(json_row, "ifIndex", ifp->ifindex);
+ json_object_int_add(json_row, "vif",
+ pim_ifp->mroute_vif_index);
+ json_object_int_add(json_row, "pktsIn",
+ (unsigned long)vreq.icount);
+ json_object_int_add(json_row, "pktsOut",
+ (unsigned long)vreq.ocount);
+ json_object_int_add(json_row, "bytesIn",
+ (unsigned long)vreq.ibytes);
+ json_object_int_add(json_row, "bytesOut",
+ (unsigned long)vreq.obytes);
+ json_object_object_add(json, ifp->name, json_row);
+ } else {
+ vty_out(vty,
+ "%-16s %-15s %3d %3d %7lu %7lu %10lu %10lu\n",
+ ifp->name, inet_ntoa(ifaddr), ifp->ifindex,
+ pim_ifp->mroute_vif_index,
+ (unsigned long)vreq.icount,
+ (unsigned long)vreq.ocount,
+ (unsigned long)vreq.ibytes,
+ (unsigned long)vreq.obytes);
+ }
+ }
- vty_out(vty, "%-16s %-15s %3d %3d %7lu %7lu %10lu %10lu\n",
- ifp->name, inet_ntoa(ifaddr), ifp->ifindex,
- pim_ifp->mroute_vif_index, (unsigned long)vreq.icount,
- (unsigned long)vreq.ocount, (unsigned long)vreq.ibytes,
- (unsigned long)vreq.obytes);
+ if (uj) {
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(
+ json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
}
}
@@ -5745,7 +5782,7 @@ static void pim_cmd_show_ip_multicast_helper(struct pim_instance *pim,
show_scan_oil_stats(pim, vty, now);
- show_multicast_interfaces(pim, vty);
+ show_multicast_interfaces(pim, vty, false);
}
DEFUN (show_ip_multicast,
@@ -5797,6 +5834,60 @@ DEFUN (show_ip_multicast_vrf_all,
return CMD_SUCCESS;
}
+DEFUN(show_ip_multicast_count,
+ show_ip_multicast_count_cmd,
+ "show ip multicast count [vrf NAME] [json]",
+ SHOW_STR IP_STR
+ "Multicast global information\n"
+ "Data packet count\n"
+ VRF_CMD_HELP_STR JSON_STR)
+{
+ int idx = 3;
+ struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
+ bool uj = use_json(argc, argv);
+
+ if (!vrf)
+ return CMD_WARNING;
+
+ show_multicast_interfaces(vrf->info, vty, uj);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(show_ip_multicast_count_vrf_all,
+ show_ip_multicast_count_vrf_all_cmd,
+ "show ip multicast count vrf all [json]",
+ SHOW_STR IP_STR
+ "Multicast global information\n"
+ "Data packet count\n"
+ VRF_CMD_HELP_STR JSON_STR)
+{
+ bool uj = use_json(argc, argv);
+ struct vrf *vrf;
+ bool first = true;
+
+ if (uj)
+ vty_out(vty, "{ ");
+
+ RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
+ if (uj) {
+ if (!first)
+ vty_out(vty, ", ");
+
+ vty_out(vty, " \"%s\": ", vrf->name);
+ first = false;
+ } else
+ vty_out(vty, "VRF: %s\n", vrf->name);
+
+ show_multicast_interfaces(vrf->info, vty, uj);
+ }
+
+ if (uj)
+ vty_out(vty, "}\n");
+
+ return CMD_SUCCESS;
+}
+
static void show_mroute(struct pim_instance *pim, struct vty *vty,
struct prefix_sg *sg, bool fill, bool uj)
{
@@ -11047,6 +11138,8 @@ void pim_cmd_init(void)
install_element(VIEW_NODE, &show_ip_pim_bsr_cmd);
install_element(VIEW_NODE, &show_ip_multicast_cmd);
install_element(VIEW_NODE, &show_ip_multicast_vrf_all_cmd);
+ install_element(VIEW_NODE, &show_ip_multicast_count_cmd);
+ install_element(VIEW_NODE, &show_ip_multicast_count_vrf_all_cmd);
install_element(VIEW_NODE, &show_ip_mroute_cmd);
install_element(VIEW_NODE, &show_ip_mroute_vrf_all_cmd);
install_element(VIEW_NODE, &show_ip_mroute_count_cmd);
diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c
index 70e06ccc4e..89fd2bd215 100644
--- a/pimd/pim_ifchannel.c
+++ b/pimd/pim_ifchannel.c
@@ -943,10 +943,13 @@ void pim_ifchannel_join_add(struct interface *ifp, struct in_addr neigh_addr,
THREAD_OFF(ch->t_ifjoin_expiry_timer);
break;
case PIM_IFJOIN_PRUNE:
- if (source_flags & PIM_ENCODE_RPT_BIT)
+ if (source_flags & PIM_ENCODE_RPT_BIT) {
pim_ifchannel_ifjoin_switch(__func__, ch,
PIM_IFJOIN_NOINFO);
- else
+ THREAD_OFF(ch->t_ifjoin_expiry_timer);
+ delete_on_noinfo(ch);
+ return;
+ } else
pim_ifchannel_ifjoin_handler(ch, pim_ifp);
break;
case PIM_IFJOIN_PRUNE_PENDING:
diff --git a/ripd/rip_nb_state.c b/ripd/rip_nb_state.c
index e88f33ec68..184c760998 100644
--- a/ripd/rip_nb_state.c
+++ b/ripd/rip_nb_state.c
@@ -175,6 +175,7 @@ ripd_instance_state_routes_route_get_next(struct nb_cb_get_next_args *args)
rn = route_top(rip->table);
else
rn = route_next((struct route_node *)args->list_entry);
+ /* Optimization: skip empty route nodes. */
while (rn && rn->info == NULL)
rn = route_next(rn);
diff --git a/ripngd/ripng_nb_state.c b/ripngd/ripng_nb_state.c
index 926573b407..02a00ac429 100644
--- a/ripngd/ripng_nb_state.c
+++ b/ripngd/ripng_nb_state.c
@@ -144,6 +144,7 @@ ripngd_instance_state_routes_route_get_next(struct nb_cb_get_next_args *args)
rn = agg_route_top(ripng->table);
else
rn = agg_route_next((struct agg_node *)args->list_entry);
+ /* Optimization: skip empty route nodes. */
while (rn && rn->info == NULL)
rn = agg_route_next(rn);
diff --git a/tests/lib/test_typelist.h b/tests/lib/test_typelist.h
index da3530e9c0..f86cadd398 100644
--- a/tests/lib/test_typelist.h
+++ b/tests/lib/test_typelist.h
@@ -25,7 +25,9 @@
#define list_hash concat(TYPE, _hash)
#define list_init concat(TYPE, _init)
#define list_fini concat(TYPE, _fini)
+#define list_const_first concat(TYPE, _const_first)
#define list_first concat(TYPE, _first)
+#define list_const_next concat(TYPE, _const_next)
#define list_next concat(TYPE, _next)
#define list_next_safe concat(TYPE, _next_safe)
#define list_count concat(TYPE, _count)
@@ -177,18 +179,29 @@ static void concat(test_, TYPE)(void)
ts_hashx("fill", "a538546a6e6ab0484e925940aa8dd02fd934408bbaed8cb66a0721841584d838");
k = 0;
- prev = NULL;
- frr_each(list, &head, item) {
+
+#if IS_ATOMIC(REALTYPE)
+ struct list_head *chead = &head;
+ struct item *citem, *cprev = NULL;
+
+ frr_each(list, chead, citem) {
+#else
+ const struct list_head *chead = &head;
+ const struct item *citem, *cprev = NULL;
+
+ frr_each(list_const, chead, citem) {
+#endif
+
#if IS_HASH(REALTYPE) || IS_HEAP(REALTYPE)
/* hash table doesn't give sorting */
- (void)prev;
+ (void)cprev;
#else
- assert(!prev || prev->val < item->val);
+ assert(!cprev || cprev->val < citem->val);
#endif
- prev = item;
+ cprev = citem;
k++;
}
- assert(list_count(&head) == k);
+ assert(list_count(chead) == k);
ts_ref("walk");
#if IS_UNIQ(REALTYPE)
diff --git a/tests/topotests/all-protocol-startup/r1/babeld.conf b/tests/topotests/all-protocol-startup/r1/babeld.conf
new file mode 100644
index 0000000000..3e119bf24d
--- /dev/null
+++ b/tests/topotests/all-protocol-startup/r1/babeld.conf
@@ -0,0 +1,4 @@
+router babel
+ network 192.168.1.1
+ network 192.168.2.1
+! \ No newline at end of file
diff --git a/tests/topotests/all-protocol-startup/r1/nhrpd.conf b/tests/topotests/all-protocol-startup/r1/nhrpd.conf
new file mode 100644
index 0000000000..74e0f12e32
--- /dev/null
+++ b/tests/topotests/all-protocol-startup/r1/nhrpd.conf
@@ -0,0 +1 @@
+! \ No newline at end of file
diff --git a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py
index f78c2b4bc0..fb211957a7 100755
--- a/tests/topotests/all-protocol-startup/test_all_protocol_startup.py
+++ b/tests/topotests/all-protocol-startup/test_all_protocol_startup.py
@@ -121,6 +121,8 @@ def setup_module(module):
# Only test LDPd if it's installed and Kernel >= 4.5
net['r%s' % i].loadConf('ldpd', '%s/r%s/ldpd.conf' % (thisDir, i))
net['r%s' % i].loadConf('sharpd')
+ net['r%s' % i].loadConf('nhrpd', '%s/r%s/nhrpd.conf' % (thisDir, i))
+ net['r%s' % i].loadConf('babeld', '%s/r%s/babeld.conf' % (thisDir, i))
net['r%s' % i].startRouter()
# For debugging after starting Quagga/FRR daemons, uncomment the next line
diff --git a/tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py b/tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py
index fd3e7fd7d3..087ba21e5e 100755
--- a/tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py
+++ b/tests/topotests/bgp-ecmp-topo2/test_ebgp_ecmp_topo2.py
@@ -295,7 +295,7 @@ def test_modify_ecmp_max_paths(request, ecmp_num, test_type):
addr_type,
dut,
input_dict_1,
- next_hop=NEXT_HOPS[addr_type],
+ next_hop=NEXT_HOPS[addr_type][:int(ecmp_num)],
protocol=protocol,
)
assert result is True, "Testcase {} : Failed \n Error: {}".format(
diff --git a/tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py b/tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py
index 94ffc71ef6..94409ff3e1 100755
--- a/tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py
+++ b/tests/topotests/bgp-ecmp-topo2/test_ibgp_ecmp_topo2.py
@@ -296,7 +296,7 @@ def test_modify_ecmp_max_paths(request, ecmp_num, test_type):
addr_type,
dut,
input_dict_1,
- next_hop=NEXT_HOPS[addr_type],
+ next_hop=NEXT_HOPS[addr_type][:int(ecmp_num)],
protocol=protocol,
)
assert result is True, "Testcase {} : Failed \n Error: {}".format(
diff --git a/tests/topotests/bgp_gr_functionality_topo1/bgp_gr_topojson_topo1.json b/tests/topotests/bgp_gr_functionality_topo1/bgp_gr_topojson_topo1.json
new file mode 100644
index 0000000000..7b3cac814f
--- /dev/null
+++ b/tests/topotests/bgp_gr_functionality_topo1/bgp_gr_topojson_topo1.json
@@ -0,0 +1,115 @@
+{
+ "ipv4base":"192.168.0.0",
+ "ipv4mask":24,
+ "ipv6base":"fd00::",
+ "ipv6mask":64,
+ "link_ip_start":{"ipv4":"192.168.0.0", "v4mask":24, "ipv6":"fd00::", "v6mask":64},
+ "lo_prefix":{"ipv4":"1.0.", "v4mask":32, "ipv6":"2001:DB8:F::", "v6mask":128},
+ "routers":{
+ "r1":{
+ "links":{
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r2-link1": {"ipv4":"auto", "ipv6":"auto"},
+ "r2-link2": {"ipv4":"auto", "ipv6":"auto"}
+ },
+ "bgp": {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"}
+ ],
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"}
+ ],
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "static_routes":[
+ {
+ "network":"100.0.10.1/32",
+ "no_of_ip":5,
+ "next_hop":"192.168.1.2"
+ },
+ {
+ "network":"1::1/128",
+ "no_of_ip":5,
+ "next_hop":"fd00:0:0:1::2"
+ }]},
+ "r2":{
+ "links":{
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r1-link1": {"ipv4":"auto", "ipv6":"auto"},
+ "r1-link2": {"ipv4":"auto", "ipv6":"auto"}
+ },
+ "bgp": {
+ "local_as": "200",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"}
+ ],
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"}
+ ],
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "static_routes":[
+ {
+ "network":"200.0.20.1/32",
+ "no_of_ip":5,
+ "next_hop":"192.168.1.1"
+ },
+ {
+ "network":"2::1/128",
+ "no_of_ip":5,
+ "next_hop":"fd00:0:0:1::1"
+ }]
+ }
+ }
+}
diff --git a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py
new file mode 100755
index 0000000000..fdc1bed522
--- /dev/null
+++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py
@@ -0,0 +1,3495 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2019 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 Gracefull Restart functionality.
+Basic Common Test steps for all the test case below :
+- Create topology (setup module)
+ Creating 2 routers topology, r1, r2 in IBGP
+- Bring up topology
+- Verify for bgp to converge
+- Configure BGP Garceful Restart on both the routers.
+
+1. Helper BGP router R1, mark and unmark IPV4 routes
+ as stale as the restarting router R2 come up within the restart time.
+2. Helper BGP router R1, mark IPV4 routes as stale and
+ deletes them as the restarting router R2 did-not come up within restart
+ time.
+3. Restart BGP router R1, detects it is connected to R2,
+ which is a helper router. Verify the restart capability i.e. R bit
+ are sent after R1 reloads and comes back.
+4. Verify that the restarting node sets "R" bit while sending the
+ BGP open messages after the node restart, only if GR is enabled.
+5. Verify if restarting node resets R bit in BGP open message
+ during normal BGP session flaps as well, even when GR restarting mode is enabled.
+ Here link flap happen due to interface UP/DOWN.
+6. Verify if restarting node resets R bit in BGP open message
+ during normal BGP session flaps as well, even when GR restarting mode is enabled.
+ Here link flap happen due to neigh router restarts
+7. Verify if restarting node resets R bit in BGP open message
+ during normal BGP session flaps when GR helper mode is enabled.
+ Here link flap happen due to interface UP/DOWN.
+8. Verify if restarting node resets R bit in BGP open message
+ during normal BGP session flaps when GR helper mode is enabled.
+ Here link flap happen due to neigh router restarts.
+9. Verify that restarting nodes set "F" bit while sending
+ the BGP open messages after it restarts, only when BGP GR is enabled.
+10. Verify that restarting nodes reset "F" bit while sending
+ the BGP open messages after it's restarts, when BGP GR is **NOT** enabled.
+11. Verify that only GR helper routers keep the stale
+ route entries, not any GR disabled router.
+12. Verify that GR helper routers keeps all the routes received
+ from restarting node if both the routers are configured as GR restarting node.
+13. Verify that GR helper routers delete all the routes
+ received from a node if both the routers are configured as GR helper node.
+14. Test Objective : After BGP neighborship is established and GR capability
+ is exchanged, transition helper router to disabled state.
+15.Test Objective : After BGP neighborship is established and GR capability
+ is exchanged, transition disabled router to helper state.
+16. Verify transition from Global Restarting to Disable and then
+ Global Disable to Restarting.
+17. Verify transition from Global Helper to Disable and then Global
+ Disable to Helper.
+18. Verify transition from Global Restart to Helper and then Global
+ Helper to Restart.
+19. Verify transition from Peer-level helper to Global Restarting.
+20. Verify transition from Peer-level restart to Global Restart.
+21. Verify transition from Peer-level disabled to Global Restart.
+22. Verify Peer-level inherit from Global Restarting mode.
+23. Verify transition from Peer-level helper to Global inherit helper.
+24. Verify transition from Peer-level restart to Global inherit helper.
+25. Verify transition from Peer-level disbale to Global inherit helper.
+26. Verify default GR functional mode is Helper.
+27. Verify transition from Peer-level Helper to Global Disable.
+28. Verify transition from Peer-level Restarting to Global Disable.
+29. Verify transition from Peer-level Disable to Global Disable.
+30. Verfiy Peer-level inherit from Global Disable mode.
+
+"""
+
+import os
+import sys
+import json
+import time
+import inspect
+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("../"))
+sys.path.append(os.path.join("../lib/"))
+
+# 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
+
+# Import topoJson from lib, to create topology and initial configuration
+from lib.topojson import build_topo_from_json, build_config_from_json
+from lib.bgp import (
+ clear_bgp,
+ verify_bgp_rib,
+ verify_graceful_restart,
+ create_router_bgp,
+ verify_r_bit,
+ verify_f_bit,
+ verify_bgp_convergence,
+ verify_graceful_restart_timers,
+)
+
+from lib.common_config import (
+ write_test_header,
+ reset_config_on_routers,
+ start_topology,
+ kill_router_daemons,
+ start_router_daemons,
+ verify_rib,
+ check_address_types,
+ write_test_footer,
+ check_router_status,
+ shutdown_bringup_interface,
+ step,
+ kill_mininet_routers_process,
+ get_frr_ipv6_linklocal,
+ create_route_maps,
+)
+
+# Reading the data from JSON File for topology and configuration creation
+jsonFile = "{}/bgp_gr_topojson_topo1.json".format(CWD)
+try:
+ with open(jsonFile, "r") as topoJson:
+ topo = json.load(topoJson)
+except IOError:
+ logger.info("Could not read file:", jsonFile)
+
+
+# Global variables
+NEXT_HOP_IP = {"ipv4": "192.168.1.10", "ipv6": "fd00:0:0:1::10"}
+NEXT_HOP_IP_1 = {"ipv4": "192.168.0.1", "ipv6": "fd00::1"}
+NEXT_HOP_IP_2 = {"ipv4": "192.168.0.2", "ipv6": "fd00::2"}
+BGP_CONVERGENCE = False
+GR_RESTART_TIMER = 20
+PREFERRED_NEXT_HOP = "link_local"
+
+
+class GenerateTopo(Topo):
+ """
+ Test topology builder
+
+ * `Topo`: Topology object
+ """
+
+ def build(self, *_args, **_opts):
+ "Build function"
+ tgen = get_topogen(self)
+
+ # This function only purpose is to create topology
+ # as defined in input json file.
+ #
+ # Create topology (setup module)
+ # Creating 2 routers topology, r1, r2in IBGP
+ # Bring up topology
+
+ # Building topology from json file
+ build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+ """
+ Sets up the pytest environment
+
+ * `mod`: module name
+ """
+
+ global ADDR_TYPES
+
+ 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(GenerateTopo, mod.__name__)
+ # ... and here it calls Mininet initialization functions.
+
+ # Kill stale mininet routers and process
+ kill_mininet_routers_process(tgen)
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start deamons and then start routers
+ start_topology(tgen)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Api call verify whether BGP is converged
+ ADDR_TYPES = check_address_types()
+
+ for addr_type in ADDR_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(mod):
+ """
+ Teardown the pytest environment
+
+ * `mod`: module name
+ """
+
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info(
+ "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+ )
+ logger.info("=" * 40)
+
+
+def configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut, peer):
+ """
+ This function groups the repetitive function calls into one function.
+ """
+
+ result = create_router_bgp(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+ clear_bgp(tgen, addr_type, dut)
+
+ return True
+
+
+def next_hop_per_address_family(
+ tgen, dut, peer, addr_type, next_hop_dict, preferred_next_hop=PREFERRED_NEXT_HOP
+):
+ """
+ This function returns link_local or global next_hop per address-family
+ """
+
+ intferface = topo["routers"][peer]["links"]["{}-link1".format(dut)]["interface"]
+ if addr_type == "ipv6" and "link_local" in preferred_next_hop:
+ next_hop = get_frr_ipv6_linklocal(tgen, peer, intf=intferface)
+ else:
+ next_hop = next_hop_dict[addr_type]
+
+ return next_hop
+
+
+def test_BGP_GR_TC_46_p1(request):
+ """
+ Test Objective : transition from Peer-level helper to Global Restarting
+ Global Mode : GR Restarting
+ PerPeer Mode : GR Helper
+ GR Mode effective : GR Helper
+
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Check router status
+ check_router_status(tgen)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ step(
+ "Configure R1 and R2 as GR restarting node in global"
+ " and helper in per-Peer-level"
+ )
+
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "graceful-restart": {"graceful-restart": True,},
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ },
+ }
+ },
+ "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}},
+ }
+
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2")
+
+ step("Verify on R2 that R1 advertises GR capabilities as a restarting node")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step("Kill BGP on R2")
+
+ kill_router_daemons(tgen, "r2", ["bgpd"])
+
+ step(
+ "Verify that R1 keeps the stale entries in RIB & FIB and R2 keeps stale entries in FIB using"
+ )
+
+ for addr_type in ADDR_TYPES:
+ protocol = "bgp"
+ next_hop = next_hop_per_address_family(
+ tgen, "r2", "r1", addr_type, NEXT_HOP_IP_1
+ )
+ input_topo = {"r1": topo["routers"]["r1"]}
+ result = verify_rib(tgen, addr_type, "r2", input_topo, next_hop, protocol)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ next_hop = next_hop_per_address_family(
+ tgen, "r1", "r2", addr_type, NEXT_HOP_IP_2
+ )
+ input_topo = {"r2": topo["routers"]["r2"]}
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_topo, next_hop)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(tgen, addr_type, "r1", input_topo, next_hop, protocol)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Bring up BGP on R1 and remove Peer-level GR config"
+ " from R1 following by a session reset"
+ )
+
+ start_router_daemons(tgen, "r2", ["bgpd"])
+
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart-helper": False}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart-helper": False}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ }
+
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2")
+
+ step("Verify on R2 that R1 advertises GR capabilities as a restarting node")
+
+ input_dict = {
+ "r1": {"bgp": {"graceful-restart": {"graceful-restart": True}}},
+ "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}},
+ }
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step("Kill BGP on R1")
+
+ kill_router_daemons(tgen, "r1", ["bgpd"])
+
+ step(
+ "Verify that R1 keeps the stale entries in FIB command and R2 keeps stale entries in RIB & FIB"
+ )
+
+ for addr_type in ADDR_TYPES:
+ protocol = "bgp"
+ next_hop = next_hop_per_address_family(
+ tgen, "r1", "r2", addr_type, NEXT_HOP_IP_2
+ )
+ input_topo = {"r2": topo["routers"]["r2"]}
+ result = verify_rib(tgen, addr_type, "r1", input_topo, next_hop, protocol)
+ assert (
+ result is True
+ ), "Testcase {} : Failed \n Routes are still present \n Error {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ next_hop = next_hop_per_address_family(
+ tgen, "r2", "r1", addr_type, NEXT_HOP_IP_1
+ )
+ input_topo = {"r1": topo["routers"]["r1"]}
+ result = verify_bgp_rib(tgen, addr_type, "r2", input_topo, next_hop)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(tgen, addr_type, "r2", input_topo, next_hop, protocol)
+ assert (
+ result is True
+ ), "Testcase {} : Failed \n Routes are still present \n Error {}".format(
+ tc_name, result
+ )
+
+ step("Start BGP on R1")
+
+ start_router_daemons(tgen, "r1", ["bgpd"])
+
+ write_test_footer(tc_name)
+
+
+def test_BGP_GR_TC_50_p1(request):
+ """
+ Test Objective : Transition from Peer-level helper to Global inherit helper
+ Global Mode : None
+ PerPeer Mode : Helper
+ GR Mode effective : GR Helper
+
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Check router status
+ check_router_status(tgen)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ step(
+ "Configure R1 as GR helper node at per Peer-level for R2"
+ " and configure R2 as global restarting node."
+ )
+
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}},
+ }
+
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2")
+
+ step("Verify on R2 that R1 advertises GR capabilities as a helper node")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step("Kill BGP on R2")
+
+ kill_router_daemons(tgen, "r2", ["bgpd"])
+
+ step(
+ "Verify that R2 keeps the stale entries in FIB & R1 keeps stale entries in RIB & FIB"
+ )
+
+ for addr_type in ADDR_TYPES:
+ protocol = "bgp"
+ next_hop = next_hop_per_address_family(
+ tgen, "r2", "r1", addr_type, NEXT_HOP_IP_1
+ )
+ input_topo = {"r1": topo["routers"]["r1"]}
+ result = verify_rib(tgen, addr_type, "r2", input_topo, next_hop, protocol)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ next_hop = next_hop_per_address_family(
+ tgen, "r1", "r2", addr_type, NEXT_HOP_IP_2
+ )
+ input_topo = {"r2": topo["routers"]["r2"]}
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_topo, next_hop)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(tgen, addr_type, "r1", input_topo, next_hop, protocol)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step("Bring up BGP on R2 and remove Peer-level GR config from R1 ")
+
+ start_router_daemons(tgen, "r2", ["bgpd"])
+
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart-helper": False}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart-helper": False}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ }
+
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2")
+
+ step("Verify on R2 that R1 still advertises GR capabilities as a helper node")
+
+ input_dict = {
+ "r1": {"bgp": {"graceful-restart": {"graceful-restart-helper": True}}},
+ "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}},
+ }
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step("Kill BGP on R2")
+
+ kill_router_daemons(tgen, "r2", ["bgpd"])
+
+ step(
+ "Verify that R2 keeps the stale entries in FIB & R1 keeps stale entries in RIB & FIB"
+ )
+
+ for addr_type in ADDR_TYPES:
+ protocol = "bgp"
+ next_hop = next_hop_per_address_family(
+ tgen, "r2", "r1", addr_type, NEXT_HOP_IP_1
+ )
+ input_topo = {"r1": topo["routers"]["r1"]}
+ result = verify_rib(tgen, addr_type, "r2", input_topo, next_hop, protocol)
+ assert (
+ result is True
+ ), "Testcase {} : Failed \n Routes are still present \n Error {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ next_hop = next_hop_per_address_family(
+ tgen, "r1", "r2", addr_type, NEXT_HOP_IP_2
+ )
+ input_topo = {"r2": topo["routers"]["r2"]}
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_topo, next_hop)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(tgen, addr_type, "r1", input_topo, next_hop, protocol)
+ assert (
+ result is True
+ ), "Testcase {} : Failed \n Routes are still present \n Error {}".format(
+ tc_name, result
+ )
+
+ step("Start BGP on R2")
+
+ start_router_daemons(tgen, "r2", ["bgpd"])
+
+ write_test_footer(tc_name)
+
+
+def test_BGP_GR_TC_51_p1(request):
+ """
+ Test Objective : Transition from Peer-level restarting to Global inherit helper
+ Global Mode : None
+ PerPeer Mode : GR Restart
+ GR Mode effective : GR Restart
+
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Check router status
+ check_router_status(tgen)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ step("Configure R1 as GR restarting node at per Peer-level for R2")
+
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}},
+ }
+
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2")
+ step("Verify on R2 that R1 advertises GR capabilities as a restarting node")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step("Kill BGP on R1")
+
+ kill_router_daemons(tgen, "r1", ["bgpd"])
+
+ step(
+ "Verify that R1 keeps the stale entries in FIB & R2 keeps stale entries in RIB & FIB"
+ )
+
+ for addr_type in ADDR_TYPES:
+ protocol = "bgp"
+ next_hop = next_hop_per_address_family(
+ tgen, "r1", "r2", addr_type, NEXT_HOP_IP_2
+ )
+ input_topo = {"r2": topo["routers"]["r2"]}
+ result = verify_rib(tgen, addr_type, "r1", input_topo, next_hop, protocol)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ next_hop = next_hop_per_address_family(
+ tgen, "r2", "r1", addr_type, NEXT_HOP_IP_1
+ )
+ input_topo = {"r1": topo["routers"]["r1"]}
+ result = verify_bgp_rib(tgen, addr_type, "r2", input_topo, next_hop)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(tgen, addr_type, "r2", input_topo, next_hop, protocol)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step("Bring up BGP on R1 and remove Peer-level GR config")
+
+ start_router_daemons(tgen, "r1", ["bgpd"])
+
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart": False}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart": False}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ }
+
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2")
+
+ step("Verify on R2 that R1 advertises GR capabilities as a helper node")
+
+ input_dict = {
+ "r1": {"bgp": {"graceful-restart": {"graceful-restart-helper": True}}},
+ "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}},
+ }
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step("Kill BGPd on R2")
+
+ kill_router_daemons(tgen, "r2", ["bgpd"])
+
+ step(
+ "Verify that R2 keeps the stale entries in FIB & R1 keeps stale entries in RIB & FIB"
+ )
+
+ for addr_type in ADDR_TYPES:
+ protocol = "bgp"
+ next_hop = next_hop_per_address_family(
+ tgen, "r2", "r1", addr_type, NEXT_HOP_IP_1
+ )
+ input_topo = {"r1": topo["routers"]["r1"]}
+ result = verify_rib(tgen, addr_type, "r2", input_topo, next_hop, protocol)
+ assert (
+ result is True
+ ), "Testcase {} : Failed \n Routes are still present \n Error {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ next_hop = next_hop_per_address_family(
+ tgen, "r1", "r2", addr_type, NEXT_HOP_IP_2
+ )
+ input_topo = {"r2": topo["routers"]["r2"]}
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_topo, next_hop)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(tgen, addr_type, "r1", input_topo, next_hop, protocol)
+ assert (
+ result is True
+ ), "Testcase {} : Failed \n Routes are still present \n Error {}".format(
+ tc_name, result
+ )
+
+ step("Start BGP on R2")
+
+ start_router_daemons(tgen, "r2", ["bgpd"])
+
+ write_test_footer(tc_name)
+
+
+def test_BGP_GR_TC_53_p1(request):
+ """
+ Test Objective : Default GR functional mode is Helper.
+ Global Mode : None
+ PerPeer Mode : None
+ GR Mode effective : GR Helper
+
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Check router status
+ check_router_status(tgen)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ step("configure R2 as global restarting node")
+
+ input_dict = {"r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}}}
+
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2")
+
+ step(
+ "Verify on R2 that R1 advertises GR capabilities as a helper node based on inherit"
+ )
+
+ input_dict = {
+ "r1": {"bgp": {"graceful-restart": {"graceful-restart-helper": True}}},
+ "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}},
+ }
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step("Kill BGPd on R2")
+
+ kill_router_daemons(tgen, "r2", ["bgpd"])
+
+ step(
+ "Verify that R2 keeps the stale entries in FIB & R1 keeps stale entries in RIB & FIB"
+ )
+
+ for addr_type in ADDR_TYPES:
+ protocol = "bgp"
+ next_hop = next_hop_per_address_family(
+ tgen, "r2", "r1", addr_type, NEXT_HOP_IP_1
+ )
+ input_topo = {"r1": topo["routers"]["r1"]}
+ result = verify_rib(tgen, addr_type, "r2", input_topo, next_hop, protocol)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ next_hop = next_hop_per_address_family(
+ tgen, "r1", "r2", addr_type, NEXT_HOP_IP_2
+ )
+ input_topo = {"r2": topo["routers"]["r2"]}
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_topo, next_hop)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(tgen, addr_type, "r1", input_topo, next_hop, protocol)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step("Start BGP on R2")
+
+ start_router_daemons(tgen, "r2", ["bgpd"])
+
+ write_test_footer(tc_name)
+
+
+def test_BGP_GR_UTP_1_3_p0(request):
+ """
+ Test Objective : Helper BGP router R1, mark and unmark IPV4 routes
+ as stale as the restarting router R2 come up within the restart time
+
+ Test Objective : Helper BGP router R1, mark IPV4 routes as stale and
+ deletes them as the restarting router R2 did-not come up within
+ restart time.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Create route-map to prefer global next-hop
+ input_dict = {
+ "r1": {
+ "route_maps": {
+ "rmap_global": [
+ {"action": "permit", "set": {"ipv6": {"nexthop": "prefer-global"}}}
+ ]
+ }
+ },
+ "r2": {
+ "route_maps": {
+ "rmap_global": [
+ {"action": "permit", "set": {"ipv6": {"nexthop": "prefer-global"}}}
+ ]
+ }
+ },
+ }
+ result = create_route_maps(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ # Configure neighbor for route map
+ input_dict_1 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {
+ "route_maps": [
+ {
+ "name": "rmap_global",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r2": {
+ "bgp": {
+ "address_family": {
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {
+ "route_maps": [
+ {
+ "name": "rmap_global",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ # Configure graceful-restart
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ "r2": {
+ "bgp": {
+ "graceful-restart": {"timer": {"restart-time": GR_RESTART_TIMER}},
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {"graceful-restart": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {"graceful-restart": True}
+ }
+ }
+ }
+ }
+ },
+ },
+ }
+ },
+ }
+
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r2", peer="r1")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r2", peer="r1"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying BGP RIB routes
+ dut = "r1"
+ peer = "r2"
+ next_hop = next_hop_per_address_family(
+ tgen, dut, peer, addr_type, NEXT_HOP_IP_2, preferred_next_hop="global"
+ )
+ input_topo = {key: topo["routers"][key] for key in ["r2"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_topo)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes
+ result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, "bgp")
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ logger.info("[Phase 2] : R2 goes for reload ")
+
+ kill_router_daemons(tgen, "r2", ["bgpd"])
+
+ logger.info(
+ "[Phase 3] : R2 is still down, restart time 120 sec."
+ " So time verify the routes are present in BGP RIB"
+ " and ZEBRA"
+ )
+
+ for addr_type in ADDR_TYPES:
+ # Verifying BGP RIB routes
+ next_hop = next_hop_per_address_family(
+ tgen, dut, peer, addr_type, NEXT_HOP_IP_2, preferred_next_hop="global"
+ )
+ result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes
+ protocol = "bgp"
+ result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ logger.info("[Phase 4] : sleep for {} sec".format(GR_RESTART_TIMER))
+ sleep(GR_RESTART_TIMER)
+
+ logger.info("[Phase 5] : Verify the routes from r2 ")
+
+ for addr_type in ADDR_TYPES:
+ # Verifying BGP RIB routes
+ next_hop = NEXT_HOP_IP_2[addr_type]
+ input_topo = {key: topo["routers"][key] for key in ["r2"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_topo, expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+ logger.info(" Expected behavior: {}".format(result))
+
+ # Verifying RIB routes
+ result = verify_rib(
+ tgen, addr_type, dut, input_topo, next_hop, "bgp", expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+ logger.info(" Expected behavior: {}".format(result))
+
+ logger.info("[Phase 5] : R2 is about to come up now ")
+ start_router_daemons(tgen, "r2", ["bgpd"])
+
+ logger.info("[Phase 5] : R2 is UP Now ! ")
+
+ for addr_type in ADDR_TYPES:
+ # Verifying GR stats
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r2", peer="r1"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_r_bit(tgen, topo, addr_type, input_dict, dut="r1", peer="r2")
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying BGP RIB routes
+ next_hop = next_hop_per_address_family(
+ tgen, dut, peer, addr_type, NEXT_HOP_IP_2, preferred_next_hop="global"
+ )
+ result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes
+ result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_BGP_GR_UTP_15_TC_9_p1(request):
+ """
+ Test Objective : Restart BGP router R1, detects it is connected to R2,
+ which is a helper router. Verify the restart capability i.e. R bit
+ are sent after R1 reloads and comes back.
+
+ Test Objective : Verify that restarting nodes reset "F" bit while sending
+ the BGP open messages after it's restarts, when BGP GR is **NOT** enabled.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Checking router status, starting if not running
+ check_router_status(tgen)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ # reset_config_on_routers(tgen)
+
+ # Create route-map to prefer global next-hop
+ input_dict = {
+ "r1": {
+ "route_maps": {
+ "rmap_global": [
+ {"action": "permit", "set": {"ipv6": {"nexthop": "prefer-global"}}}
+ ]
+ }
+ },
+ "r2": {
+ "route_maps": {
+ "rmap_global": [
+ {"action": "permit", "set": {"ipv6": {"nexthop": "prefer-global"}}}
+ ]
+ }
+ },
+ }
+ result = create_route_maps(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ # Configure neighbor for route map
+ input_dict_1 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {
+ "route_maps": [
+ {
+ "name": "rmap_global",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r2": {
+ "bgp": {
+ "address_family": {
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {
+ "route_maps": [
+ {
+ "name": "rmap_global",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ logger.info(
+ "[Phase 1] : Test Setup " "[Helper Mode]R1-----R2[Restart Mode] initialized "
+ )
+
+ # Configure graceful-restart
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ "r2": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ }
+
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying BGP RIB routes
+ dut = "r1"
+ peer = "r2"
+ next_hop = next_hop_per_address_family(
+ tgen, dut, peer, addr_type, NEXT_HOP_IP_2, preferred_next_hop="global"
+ )
+ input_topo = {key: topo["routers"][key] for key in ["r2"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes
+ protocol = "bgp"
+ result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ logger.info("[Phase 2] : R1 goes for reload ")
+
+ kill_router_daemons(tgen, "r1", ["bgpd"])
+
+ logger.info("[Phase 6] : R1 is about to come up now ")
+ start_router_daemons(tgen, "r1", ["bgpd"])
+
+ for addr_type in ADDR_TYPES:
+ # Verifying GR stats
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_r_bit(tgen, topo, addr_type, input_dict, dut="r2", peer="r1")
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying BGP RIB routes
+ next_hop = next_hop_per_address_family(
+ tgen, dut, peer, addr_type, NEXT_HOP_IP_2, preferred_next_hop="global"
+ )
+ result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes
+ result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_r_bit(tgen, topo, addr_type, input_dict, dut="r1", peer="r2")
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_f_bit(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r2", expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_BGP_GR_UTP_35_p1(request):
+ """
+ Test Objective : Restart BGP router R1 connected to R2,
+ which is a restart router.
+ R1 should not send any GR capability in the open message,
+ however it would process open message from R2 with GR -restart
+ capability, but would not perform any BGP GR functionality.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Check router status
+ check_router_status(tgen)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ logger.info(
+ "[Phase 1] : Test Setup" " [Disable Mode]R1-----R2[Restart Mode] initialized "
+ )
+
+ # Configure graceful-restart
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart-disable": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart-disable": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ "r2": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {"graceful-restart": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {"graceful-restart": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ }
+
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying BGP RIB routes
+ dut = "r1"
+ peer = "r2"
+ next_hop = next_hop_per_address_family(
+ tgen, dut, peer, addr_type, NEXT_HOP_IP_2
+ )
+ input_topo = {key: topo["routers"][key] for key in ["r2"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes
+ protocol = "bgp"
+ result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ logger.info("[Phase 2] : R1 goes for reload ")
+
+ kill_router_daemons(tgen, "r1", ["bgpd"])
+
+ logger.info("[Phase 3] : R1 is about to come up now ")
+ start_router_daemons(tgen, "r1", ["bgpd"])
+
+ logger.info("[Phase 4] : R2 is UP now, so time to collect GR stats ")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying BGP RIB routes
+ next_hop = next_hop_per_address_family(
+ tgen, dut, peer, addr_type, NEXT_HOP_IP_2
+ )
+ input_topo = {key: topo["routers"][key] for key in ["r2"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes
+ result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_BGP_GR_TC_4_p0(request):
+ """
+ Test Objective : Verify that the restarting node sets "R" bit while sending the
+ BGP open messages after the node restart, only if GR is enabled.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Check router status
+ check_router_status(tgen)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ logger.info(
+ "[Phase 1] : Test Setup" " [Restart Mode]R1-----R2[Helper Mode] initialized "
+ )
+
+ # Configure graceful-restart
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ "r2": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ }
+
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying BGP RIB routes
+ dut = "r1"
+ peer = "r2"
+ next_hop = next_hop_per_address_family(
+ tgen, dut, peer, addr_type, NEXT_HOP_IP_2
+ )
+ input_topo = {key: topo["routers"][key] for key in ["r2"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes
+ protocol = "bgp"
+ result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ logger.info("[Phase 2] : R2 goes for reload ")
+
+ kill_router_daemons(tgen, "r2", ["bgpd"])
+
+ logger.info(
+ "[Phase 3] : R2 is still down, restart time {} sec."
+ "So time verify the routes are present in BGP RIB and ZEBRA ".format(
+ GR_RESTART_TIMER
+ )
+ )
+
+ for addr_type in ADDR_TYPES:
+ # Verifying BGP RIB routes
+ next_hop = next_hop_per_address_family(
+ tgen, dut, peer, addr_type, NEXT_HOP_IP_2
+ )
+ input_topo = {key: topo["routers"][key] for key in ["r2"]}
+ result = verify_bgp_rib(
+ tgen, addr_type, dut, input_topo, next_hop, expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+ logger.info(" Expected behavior: {}".format(result))
+
+ # Verifying RIB routes
+ result = verify_rib(
+ tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+ logger.info(" Expected behavior: {}".format(result))
+
+ logger.info("[Phase 5] : R2 is about to come up now ")
+ start_router_daemons(tgen, "r2", ["bgpd"])
+
+ logger.info("[Phase 4] : R2 is UP now, so time to collect GR stats ")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_r_bit(tgen, topo, addr_type, input_dict, dut="r1", peer="r2")
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying BGP RIB routes
+ next_hop = next_hop_per_address_family(
+ tgen, dut, peer, addr_type, NEXT_HOP_IP_2
+ )
+ input_topo = {key: topo["routers"][key] for key in ["r2"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes
+ result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_BGP_GR_TC_5_1_2_p1(request):
+ """
+ Test Objective : Verify if restarting node resets R bit in BGP open message
+ during normal BGP session flaps as well, even when GR restarting mode is enabled.
+ Here link flap happen due to interface UP/DOWN.
+
+ """
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Check router status
+ check_router_status(tgen)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ logger.info(
+ "[Phase 1] : Test Setup" " [Restart Mode]R1-----R2[Restart Mode] initialized "
+ )
+
+ # Configure graceful-restart
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ "r2": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {"graceful-restart": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {"graceful-restart": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ }
+
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying BGP RIB routes
+ dut = "r1"
+ peer = "r2"
+ next_hop = next_hop_per_address_family(
+ tgen, dut, peer, addr_type, NEXT_HOP_IP_2
+ )
+ input_topo = {key: topo["routers"][key] for key in ["r2"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes
+ protocol = "bgp"
+ result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ logger.info("[Phase 2] : Now flap the link running the BGP session ")
+ # Shutdown interface
+ intf = "r2-r1-eth0"
+ shutdown_bringup_interface(tgen, "r2", intf)
+
+ # Bring up Interface
+ shutdown_bringup_interface(tgen, dut, intf, ifaceaction=True)
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_r_bit(tgen, topo, addr_type, input_dict, dut="r1", peer="r2")
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ logger.info("[Phase 2] : Restart BGPd on router R2. ")
+ kill_router_daemons(tgen, "r2", ["bgpd"])
+
+ start_router_daemons(tgen, "r2", ["bgpd"])
+
+ logger.info("[Phase 4] : R2 is UP now, so time to collect GR stats ")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_r_bit(tgen, topo, addr_type, input_dict, dut="r1", peer="r2")
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying BGP RIB routes
+ next_hop = next_hop_per_address_family(
+ tgen, dut, peer, addr_type, NEXT_HOP_IP_2
+ )
+ input_topo = {key: topo["routers"][key] for key in ["r2"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes
+ result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_BGP_GR_TC_6_1_2_p1(request):
+ """
+ Test Objective : Verify if restarting node resets R bit in BGP
+ open message during normal BGP session flaps when GR is disabled.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Check router status
+ check_router_status(tgen)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ logger.info(
+ "[Phase 1] : Test Setup" "[Restart Mode]R1-----R2[Helper Mode] initialized "
+ )
+
+ # Configure graceful-restart
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ "r2": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ }
+
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying BGP RIB routes
+ dut = "r1"
+ peer = "r2"
+ next_hop = next_hop_per_address_family(
+ tgen, dut, peer, addr_type, NEXT_HOP_IP_2
+ )
+ input_topo = {key: topo["routers"][key] for key in ["r2"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes
+ protocol = "bgp"
+ result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ logger.info("[Phase 1] : Changing mode" "[Disable Mode]R1-----R2[Helper Mode]")
+
+ # Configure graceful-restart
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart-disable": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart-disable": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+ clear_bgp(tgen, addr_type, "r1")
+ clear_bgp(tgen, addr_type, "r2")
+
+ # Verify GR stats
+ input_dict = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart-disable": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart-disable": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ }
+
+ # here the verify_graceful_restart fro the neighbor would be
+ # "NotReceived" as the latest GR config is not yet applied.
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ logger.info("[Phase 2] : Now flap the link running the BGP session ")
+ # Shutdown interface
+ intf = "r2-r1-eth0"
+ shutdown_bringup_interface(tgen, "r2", intf)
+
+ # Bring up Interface
+ shutdown_bringup_interface(tgen, dut, intf, ifaceaction=True)
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_r_bit(
+ tgen, topo, addr_type, input_dict, dut="r2", peer="r1", expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ logger.info("Restart BGPd on R2 ")
+ kill_router_daemons(tgen, "r2", ["bgpd"])
+
+ start_router_daemons(tgen, "r2", ["bgpd"])
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_r_bit(
+ tgen, topo, addr_type, input_dict, dut="r2", peer="r1", expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_BGP_GR_TC_8_p1(request):
+ """
+ Test Objective : Verify that restarting nodes set "F" bit while sending
+ the BGP open messages after it restarts, only when BGP GR is enabled.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Check router status
+ check_router_status(tgen)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ logger.info(
+ "[Phase 1] : Test Setup" " [Restart Mode]R1-----R2[Restart Mode] initialized "
+ )
+
+ # Configure graceful-restart
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "graceful-restart": {"preserve-fw-state": True},
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart": True}
+ }
+ }
+ }
+ }
+ },
+ },
+ }
+ },
+ "r2": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {"graceful-restart": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {"graceful-restart": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ }
+
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying BGP RIB routes
+ dut = "r1"
+ peer = "r2"
+ next_hop = next_hop_per_address_family(
+ tgen, dut, peer, addr_type, NEXT_HOP_IP_2
+ )
+ input_topo = {key: topo["routers"][key] for key in ["r2"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes
+ protocol = "bgp"
+ result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ logger.info("[Phase 2] : R1 goes for reload ")
+
+ kill_router_daemons(tgen, "r1", ["bgpd"])
+
+ logger.info("[Phase 3] : R1 is about to come up now ")
+ start_router_daemons(tgen, "r1", ["bgpd"])
+
+ logger.info("[Phase 4] : R2 is UP now, so time to collect GR stats ")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_r_bit(tgen, topo, addr_type, input_dict, dut="r2", peer="r1")
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_f_bit(tgen, topo, addr_type, input_dict, dut="r2", peer="r1")
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_BGP_GR_TC_17_p1(request):
+ """
+ Test Objective : Verify that only GR helper routers keep the stale
+ route entries, not any GR disabled router.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Check router status
+ check_router_status(tgen)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ logger.info("[Phase 1] : Test Setup [Disable]R1-----R2[Restart] initialized ")
+
+ # Configure graceful-restart
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "graceful-restart": {
+ "graceful-restart": True,
+ "preserve-fw-state": True,
+ },
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart-disable": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart-disable": True}
+ }
+ }
+ }
+ }
+ },
+ },
+ }
+ },
+ "r2": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {"graceful-restart": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {"graceful-restart": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ }
+
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying BGP RIB routes
+ dut = "r1"
+ peer = "r2"
+ next_hop = next_hop_per_address_family(
+ tgen, dut, peer, addr_type, NEXT_HOP_IP_2
+ )
+ input_topo = {key: topo["routers"][key] for key in ["r2"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes
+ protocol = "bgp"
+ result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ logger.info("[Phase 2] : R2 goes for reload ")
+
+ kill_router_daemons(tgen, "r2", ["bgpd"])
+
+ logger.info(
+ "[Phase 3] : R2 is still down, restart time 120 sec."
+ " So time verify the routes are present in BGP RIB and ZEBRA "
+ )
+
+ for addr_type in ADDR_TYPES:
+ # Verifying BGP RIB routes
+ next_hop = next_hop_per_address_family(
+ tgen, dut, peer, addr_type, NEXT_HOP_IP_2
+ )
+ input_topo = {key: topo["routers"][key] for key in ["r2"]}
+ result = verify_bgp_rib(
+ tgen, addr_type, dut, input_topo, next_hop, expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+ logger.info(" Expected behavior: {}".format(result))
+
+ # Verifying RIB routes
+ result = verify_rib(
+ tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+ logger.info(" Expected behavior: {}".format(result))
+
+ logger.info("[Phase 5] : R2 is about to come up now ")
+ start_router_daemons(tgen, "r2", ["bgpd"])
+
+ logger.info("[Phase 4] : R2 is UP now, so time to collect GR stats ")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_r_bit(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r2", expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying BGP RIB routes
+ next_hop = next_hop_per_address_family(
+ tgen, dut, peer, addr_type, NEXT_HOP_IP_2
+ )
+ input_topo = {key: topo["routers"][key] for key in ["r2"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes
+ result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_BGP_GR_TC_19_p1(request):
+ """
+ Test Objective : Verify that GR helper routers keeps all the routes received
+ from restarting node if both the routers are configured as GR restarting node.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Check router status
+ check_router_status(tgen)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ logger.info("[Phase 1] : Test Setup [Helper]R1-----R2[Restart] initialized ")
+
+ # Configure graceful-restart
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "graceful-restart": {
+ "graceful-restart": True,
+ "preserve-fw-state": True,
+ },
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ },
+ }
+ },
+ "r2": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {"graceful-restart": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {"graceful-restart": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ }
+
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying BGP RIB routes
+ dut = "r1"
+ peer = "r2"
+ next_hop = next_hop_per_address_family(
+ tgen, dut, peer, addr_type, NEXT_HOP_IP_2
+ )
+ input_topo = {key: topo["routers"][key] for key in ["r2"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes
+ protocol = "bgp"
+ result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ logger.info(
+ "[Phase 2] : R1's Gr state cahnge to Graceful"
+ " Restart without resetting the session "
+ )
+
+ # Configure graceful-restart
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ logger.info(
+ "[Phase 3] : R2 is still down, restart time 120 sec."
+ " So time verify the routes are present in BGP RIB and ZEBRA "
+ )
+
+ for addr_type in ADDR_TYPES:
+ # Verifying BGP RIB routes
+ next_hop = next_hop_per_address_family(
+ tgen, dut, peer, addr_type, NEXT_HOP_IP_2
+ )
+ input_topo = {key: topo["routers"][key] for key in ["r2"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes
+ result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_BGP_GR_TC_20_p1(request):
+ """
+ Test Objective : Verify that GR helper routers delete all the routes
+ received from a node if both the routers are configured as GR helper node.
+ """
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Check router status
+ check_router_status(tgen)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ logger.info("[Phase 1] : Test Setup [Helper]R1-----R2[Helper] initialized ")
+
+ # Configure graceful-restart
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "graceful-restart": {
+ "graceful-restart": True,
+ "preserve-fw-state": True,
+ },
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ },
+ }
+ },
+ "r2": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ }
+
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying BGP RIB routes
+ dut = "r1"
+ peer = "r2"
+ next_hop = next_hop_per_address_family(
+ tgen, dut, peer, addr_type, NEXT_HOP_IP_2
+ )
+ input_topo = {key: topo["routers"][key] for key in ["r2"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes
+ protocol = "bgp"
+ result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ kill_router_daemons(tgen, "r2", ["bgpd"])
+
+ for addr_type in ADDR_TYPES:
+ # Verifying BGP RIB routes
+ next_hop = next_hop_per_address_family(
+ tgen, dut, peer, addr_type, NEXT_HOP_IP_2
+ )
+ input_topo = {key: topo["routers"][key] for key in ["r2"]}
+ result = verify_bgp_rib(
+ tgen, addr_type, dut, input_topo, next_hop, expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+ logger.info(" Expected behavior: {}".format(result))
+
+ # Verifying RIB routes
+ result = verify_rib(
+ tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+ logger.info(" Expected behavior: {}".format(result))
+
+ logger.info("[Phase 5] : R2 is about to come up now ")
+
+ start_router_daemons(tgen, "r2", ["bgpd"])
+
+ logger.info("[Phase 4] : R2 is UP now, so time to collect GR stats ")
+
+ for addr_type in ADDR_TYPES:
+ # Verifying BGP RIB routes
+ next_hop = next_hop_per_address_family(
+ tgen, dut, peer, addr_type, NEXT_HOP_IP_2
+ )
+ input_topo = {key: topo["routers"][key] for key in ["r2"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes
+ result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_BGP_GR_TC_31_1_p1(request):
+ """
+ After BGP neighborship is established and GR capability is exchanged,
+ transition restarting router to disabled state and vice versa.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Check router status
+ check_router_status(tgen)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ logger.info(
+ "[Phase 1] : Test Setup" " [Helper Mode]R2-----R1[Restart Mode] initialized "
+ )
+
+ # Configure graceful-restart
+ input_dict = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ "r1": {
+ "bgp": {
+ "graceful-restart": {"preserve-fw-state": True},
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart": True}
+ }
+ }
+ }
+ }
+ },
+ },
+ }
+ },
+ }
+
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying BGP RIB routes
+ dut = "r1"
+ peer = "r2"
+ protocol = "bgp"
+ next_hop = next_hop_per_address_family(
+ tgen, dut, peer, addr_type, NEXT_HOP_IP_2
+ )
+ input_topo = {key: topo["routers"][key] for key in ["r2"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes
+ result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ logger.info("[Phase 2] : R1 Goes from Restart to Disable Mode ")
+
+ # Configure graceful-restart
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart-disable": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart-disable": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+ clear_bgp(tgen, addr_type, "r1")
+ clear_bgp(tgen, addr_type, "r2")
+
+ # Verify GR stats
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart-disable": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart-disable": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ "r2": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ }
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ logger.info("[Phase 2] : R1 goes for reload ")
+
+ kill_router_daemons(tgen, "r1", ["bgpd"])
+
+ logger.info(
+ "[Phase 3] : R1 is still down, restart time 120 sec."
+ " So time verify the routes are not present in BGP RIB and ZEBRA"
+ )
+
+ for addr_type in ADDR_TYPES:
+ # Verifying RIB routes
+ next_hop = next_hop_per_address_family(
+ tgen, dut, peer, addr_type, NEXT_HOP_IP_2
+ )
+ input_topo = {key: topo["routers"][key] for key in ["r2"]}
+ result = verify_rib(
+ tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ logger.info("[Phase 4] : R1 is about to come up now ")
+ start_router_daemons(tgen, "r1", ["bgpd"])
+
+ logger.info("[Phase 5] : R1 is UP now, so time to collect GR stats ")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying BGP RIB routes
+ next_hop = next_hop_per_address_family(
+ tgen, dut, peer, addr_type, NEXT_HOP_IP_2
+ )
+ input_topo = {key: topo["routers"][key] for key in ["r2"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes
+ result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_BGP_GR_TC_31_2_p1(request):
+ """
+ After BGP neighborship is established and GR capability is exchanged,
+ transition restarting router to disabled state and vice versa.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Check router status
+ check_router_status(tgen)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ logger.info(
+ "[Phase 1] : Test Setup " "[Disable Mode]R1-----R2[Restart Mode] initialized "
+ )
+
+ # Configure graceful-restart
+ input_dict = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart-disable": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart-disable": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ }
+
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying BGP RIB routes
+ dut = "r1"
+ peer = "r2"
+ next_hop = next_hop_per_address_family(
+ tgen, dut, peer, addr_type, NEXT_HOP_IP_2
+ )
+ input_topo = {key: topo["routers"][key] for key in ["r2"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes
+ protocol = "bgp"
+ result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ logger.info("[Phase 2] : R2 Goes from Disable to Restart Mode ")
+
+ # Configure graceful-restart
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "graceful-restart": {"preserve-fw-state": True},
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart": True}
+ }
+ }
+ }
+ }
+ },
+ },
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+ clear_bgp(tgen, addr_type, "r1")
+ clear_bgp(tgen, addr_type, "r2")
+
+ # Verify GR stats
+ input_dict = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"graceful-restart": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ }
+
+ # here the verify_graceful_restart fro the neighbor would be
+ # "NotReceived" as the latest GR config is not yet applied.
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ logger.info("[Phase 3] : R1 goes for reload ")
+
+ kill_router_daemons(tgen, "r1", ["bgpd"])
+
+ logger.info(
+ "[Phase 4] : R1 is still down, restart time 120 sec."
+ " So time verify the routes are present in BGP RIB and ZEBRA "
+ )
+
+ for addr_type in ADDR_TYPES:
+ # Verifying RIB routes
+ next_hop = next_hop_per_address_family(
+ tgen, dut, peer, addr_type, NEXT_HOP_IP_2
+ )
+ input_topo = {key: topo["routers"][key] for key in ["r2"]}
+ result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ logger.info("[Phase 6] : R1 is about to come up now ")
+ start_router_daemons(tgen, "r1", ["bgpd"])
+
+ logger.info("[Phase 4] : R1 is UP now, so time to collect GR stats ")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying BGP RIB routes
+ next_hop = next_hop_per_address_family(
+ tgen, dut, peer, addr_type, NEXT_HOP_IP_2
+ )
+ input_topo = {key: topo["routers"][key] for key in ["r2"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes
+ result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol)
+ 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_gr_functionality_topo2/bgp_gr_topojson_topo2.json b/tests/topotests/bgp_gr_functionality_topo2/bgp_gr_topojson_topo2.json
new file mode 100644
index 0000000000..75f192d3b6
--- /dev/null
+++ b/tests/topotests/bgp_gr_functionality_topo2/bgp_gr_topojson_topo2.json
@@ -0,0 +1,334 @@
+{
+ "ipv4base":"192.168.0.0",
+ "ipv4mask":24,
+ "ipv6base":"fd00::",
+ "ipv6mask":64,
+ "link_ip_start":{"ipv4":"192.168.0.0", "v4mask":24, "ipv6":"fd00::", "v6mask":64},
+ "lo_prefix":{"ipv4":"1.0.", "v4mask":32, "ipv6":"2001:DB8:F::", "v6mask":128},
+ "routers":{
+ "r1":{
+ "links":{
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r2": {"ipv4":"auto", "ipv6":"auto"},
+ "r3": {"ipv4":"auto", "ipv6":"auto"},
+ "r5": {"ipv4":"auto", "ipv6":"auto"},
+ "r6": {"ipv4":"auto", "ipv6":"auto"}
+ },
+ "bgp": {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": "101.0.20.1/32",
+ "no_of_network": 5
+ }
+ ],
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r1": {}
+ }
+ },
+ "r5": {
+ "dest_link": {
+ "r1": {}
+ }
+ },
+ "r6": {
+ "dest_link": {
+ "r1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": "1::1/128",
+ "no_of_network": 5
+ }
+ ],
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1": {
+ }
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r1": {
+ }
+ }
+ },
+ "r5": {
+ "dest_link": {
+ "r1": {
+ }
+ }
+ },
+ "r6": {
+ "dest_link": {
+ "r1": {
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r2":{
+ "links":{
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r1": {"ipv4":"auto", "ipv6":"auto"}
+ },
+ "bgp":{
+ "local_as": "200",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": "102.0.20.1/32",
+ "no_of_network": 5
+ }
+ ],
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": "2::1/128",
+ "no_of_network": 5
+ }
+ ],
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2": {
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r3":{
+ "links":{
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r1": {"ipv4":"auto", "ipv6":"auto"},
+ "r4": {"ipv4":"auto", "ipv6":"auto"}
+ },
+ "bgp":{
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": "103.0.20.1/32",
+ "no_of_network": 5
+ }
+ ],
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {}
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": "3::1/128",
+ "no_of_network": 5
+ }
+ ],
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3": {
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r4":{
+ "links":{
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r3": {"ipv4":"auto", "ipv6":"auto"}
+ },
+ "bgp":{
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": "104.0.20.1/32",
+ "no_of_network": 5
+ }
+ ],
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r4": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": "4::1/128",
+ "no_of_network": 5
+ }
+ ],
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r4": {
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r5":{
+ "links":{
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r1": {"ipv4":"auto", "ipv6":"auto"}
+ },
+ "bgp":{
+ "local_as": "500",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": "105.0.20.1/32",
+ "no_of_network": 5
+ }
+ ],
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r5": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": "5::1/128",
+ "no_of_network": 5
+ }
+ ],
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r5": {
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r6":{
+ "links":{
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r1": {"ipv4":"auto", "ipv6":"auto"}
+ },
+ "bgp":{
+ "local_as": "600",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": "106.0.20.1/32",
+ "no_of_network": 5
+ }
+ ],
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r6": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": "6::1/128",
+ "no_of_network": 5
+ }
+ ],
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r6": {
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py
new file mode 100755
index 0000000000..83a04f491f
--- /dev/null
+++ b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py
@@ -0,0 +1,3085 @@
+#!/usr/bin/env python
+#
+# Copyright (c) 2019 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 Graceful Restart functionality.
+Basic Common Test steps for all the test case below :
+- Create topology (setup module)
+ Creating 7 routers topology
+- Bring up topology
+- Verify for bgp to converge
+- Configure BGP Graceful Restart on both the routers.
+
+TC_1_2:
+ Verify that EOR message is sent out only after initial convergence
+ Verify whether EOR message is received from all the peers after restart
+TC_3:
+ Verify the selection deferral timer functionality when EOR is not sent
+ by the helper router
+TC_11:
+ Verify that selection-deferral timer sets the maximum time to
+ avoid deadlock during which the best-path
+TC_10:
+ Test Objective : Test GR scenarios on helper router by enabling
+ Graceful Restart for multiple address families.
+TC_15:
+ Test Objective : Test GR scenarios by enabling Graceful Restart
+ for multiple address families..
+TC_16:
+ Test Objective : Verify BGP-GR feature when restarting node
+ is a transit router for it's iBGP peers.
+TC_18:
+ Test Objective : Verify that GR helper router deletes stale routes
+ received from restarting node, if GR capability is not present in
+TC_19:
+ Test Objective : Verify that GR routers keeps all the routes
+ received from restarting node if both the routers are
+TC_26:
+ Test Objective : Test GR scenarios on helper router by enabling
+ Graceful Restart for multiple address families.
+TC_28:
+ Test Objective : Verify if helper node goes down before restarting
+ node comes up online, helper node sets the R-bit to avoid dead-lock
+TC_29:
+ Test Objective : Change timers on the fly, and
+ verify if it takes immediate effect.
+TC_33:
+ Test Objective : Helper router receives same prefixes from two
+ different routers (GR-restarting and GR-disabled). Keeps the
+TC_34_1:
+ Test Objective : Restarting node doesn't preserve forwarding
+ state, helper router should not keep the stale entries.
+TC_34_2:
+ Test Objective : Restarting node doesn't preserve the forwarding
+ state verify the behaviour on helper node, if it still keeps the
+TC_32:
+ Test Objective : Restarting node is connected to multiple helper
+ nodes, one of them doesn't send EOR to restarting router. Verify
+TC_37:
+ Test Objective : Verify if helper node restarts before sending the
+ EOR message, restarting node doesn't wait until stale path timer
+TC_30:
+ Test Objective : Restarting node removes stale routes from Zebra
+ after receiving an EOR from helper router.
+
+"""
+
+import os
+import sys
+import json
+import time
+import pytest
+from time import sleep
+from copy import deepcopy
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join("../"))
+sys.path.append(os.path.join("../lib/"))
+
+# 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
+
+# Import topoJson from lib, to create topology and initial configuration
+from lib.topojson import build_topo_from_json, build_config_from_json
+from lib.bgp import (
+ clear_bgp,
+ verify_bgp_rib,
+ verify_graceful_restart,
+ create_router_bgp,
+ verify_r_bit,
+ verify_eor,
+ verify_f_bit,
+ verify_bgp_convergence,
+ verify_gr_address_family,
+ modify_bgp_config_when_bgpd_down,
+ verify_graceful_restart_timers,
+)
+
+from lib.common_config import (
+ write_test_header,
+ reset_config_on_routers,
+ start_topology,
+ kill_router_daemons,
+ start_router_daemons,
+ verify_rib,
+ check_address_types,
+ write_test_footer,
+ check_router_status,
+ shutdown_bringup_interface,
+ step,
+ kill_mininet_routers_process,
+ get_frr_ipv6_linklocal,
+ create_route_maps,
+)
+
+# Reading the data from JSON File for topology and configuration creation
+jsonFile = "{}/bgp_gr_topojson_topo2.json".format(CWD)
+try:
+ with open(jsonFile, "r") as topoJson:
+ topo = json.load(topoJson)
+except IOError:
+ logger.info("Could not read file:", jsonFile)
+
+# Global variables
+BGP_CONVERGENCE = False
+GR_RESTART_TIMER = 5
+GR_SELECT_DEFER_TIMER = 5
+PREFERRED_NEXT_HOP = "link_local"
+NEXT_HOP_4 = ["192.168.1.1", "192.168.4.2"]
+NEXT_HOP_6 = ["fd00:0:0:1::1", "fd00:0:0:4::2"]
+
+
+class GenerateTopo(Topo):
+ """
+ Test topology builder
+
+ * `Topo`: Topology object
+ """
+
+ def build(self, *_args, **_opts):
+ "Build function"
+ tgen = get_topogen(self)
+
+ # This function only purpose is to create topology
+ # as defined in input json file.
+ #
+ # Create topology (setup module)
+ # Creating 2 routers topology, r1, r2in IBGP
+ # Bring up topology
+
+ # Building topology from json file
+ build_topo_from_json(tgen, topo)
+
+
+def setup_module(mod):
+ """
+ Sets up the pytest environment
+
+ * `mod`: module name
+ """
+
+ global ADDR_TYPES
+
+ 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(GenerateTopo, mod.__name__)
+ # ... and here it calls Mininet initialization functions.
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start deamons and then start routers
+ start_topology(tgen)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ # Api call verify whether BGP is converged
+ ADDR_TYPES = check_address_types()
+
+ for addr_type in ADDR_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(mod):
+ """
+ Teardown the pytest environment
+
+ * `mod`: module name
+ """
+
+ logger.info("Running teardown_module to delete topology")
+
+ tgen = get_topogen()
+
+ # Stop toplogy and Remove tmp files
+ tgen.stop_topology()
+
+ logger.info(
+ "Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
+ )
+ logger.info("=" * 40)
+
+
+def configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut, peer):
+ """
+ This function groups the repetitive function calls into one function.
+ """
+
+ result = create_router_bgp(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+ clear_bgp(tgen, addr_type, dut)
+
+ return True
+
+
+def next_hop_per_address_family(tgen, dut, peer, addr_type, next_hop_dict):
+ """
+ This function returns link_local or global next_hop per address-family
+ """
+
+ intferface = topo["routers"][peer]["links"]["{}-link1".format(dut)]["interface"]
+ if addr_type == "ipv6" and "link_local" in PREFERRED_NEXT_HOP:
+ next_hop = get_frr_ipv6_linklocal(tgen, peer, intf=intferface)
+ else:
+ next_hop = next_hop_dict[addr_type]
+
+ return next_hop
+
+
+def test_BGP_GR_TC_1_2_p0(request):
+ """
+ Verify that EOR message is sent out only after initial convergence
+ Verify whether EOR message is received from all the peers after restart
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Check router status
+ check_router_status(tgen)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ logger.info(
+ "Verify EOR Sent and Received : BGP_GR_TC_1_2 >> "
+ "BGP GR [Helper Mode]R3-----R1[Restart Mode] "
+ )
+
+ # Configure graceful-restart
+ input_dict = {
+ "r3": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ "r1": {
+ "bgp": {
+ "graceful-restart": {
+ "graceful-restart": True,
+ "preserve-fw-state": True,
+ },
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {"dest_link": {"r1": {"graceful-restart": True}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {"dest_link": {"r1": {"graceful-restart": True}}}
+ }
+ }
+ },
+ },
+ }
+ },
+ }
+
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r3"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying BGP RIB routes received from router R3
+ dut = "r1"
+ input_dict_1 = {key: topo["routers"][key] for key in ["r3"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ logger.info("R1 goes for reload")
+ kill_router_daemons(tgen, "r1", ["bgpd"])
+
+ for addr_type in ADDR_TYPES:
+ # Verifying RIB routes
+ input_dict_1 = {key: topo["routers"][key] for key in ["r3"]}
+ # Verifying RIB routes
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ logger.info("Starting bgpd process")
+ start_router_daemons(tgen, "r1", ["bgpd"])
+ logger.info("R1 is UP Now")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r3"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying BGP RIB routes received from router R3
+ input_dict_1 = {key: topo["routers"][key] for key in ["r3"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying EOR on restarting router
+ result = verify_eor(tgen, topo, addr_type, input_dict, dut="r3", peer="r1")
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_BGP_GR_TC_3_p0(request):
+ """
+ Verify the selection deferral timer functionality when EOR is not sent
+ by the helper router
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Check router status
+ check_router_status(tgen)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ logger.info(
+ " Verify route download to RIB: BGP_GR_TC_3 >> "
+ "BGP GR [Helper Mode]R1-----R2[Restart Mode] "
+ )
+
+ # Configure graceful-restart
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "graceful-restart": {"disable-eor": True,},
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ },
+ }
+ },
+ "r2": {
+ "bgp": {
+ "graceful-restart": {
+ "graceful-restart": True,
+ "preserve-fw-state": True,
+ "timer": {"select-defer-time": GR_SELECT_DEFER_TIMER},
+ },
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {"dest_link": {"r2": {"graceful-restart": True}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {"dest_link": {"r2": {"graceful-restart": True}}}
+ }
+ }
+ },
+ },
+ }
+ },
+ }
+
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying BGP RIB routes received from router R1
+ dut = "r2"
+ input_dict_1 = {key: topo["routers"][key] for key in ["r1"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ logger.info("R2 goes for reload ")
+ kill_router_daemons(tgen, "r2", ["bgpd"])
+
+ logger.info("R2 is about to come up now")
+ start_router_daemons(tgen, "r2", ["bgpd"])
+ logger.info("R2 is UP Now")
+
+ for addr_type in ADDR_TYPES:
+ # Verifying BGP RIB routes received from router R1
+ input_dict_1 = {key: topo["routers"][key] for key in ["r1"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verify EOR on restarting router
+ result = verify_eor(
+ tgen, topo, addr_type, input_dict, dut="r2", peer="r1", expected=False
+ )
+ assert result is not True, (
+ "Testcase " + tc_name + " : Failed \n Error: {}".format(result)
+ )
+
+ logger.info(
+ "Waiting for selection deferral timer({} sec)..".format(GR_SELECT_DEFER_TIMER)
+ )
+ sleep(GR_SELECT_DEFER_TIMER)
+
+ for addr_type in ADDR_TYPES:
+ # Verifying RIB routes
+ result = verify_rib(tgen, addr_type, "r2", input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_BGP_GR_TC_11_p0(request):
+ """
+ Verify that selection-deferral timer sets the maximum time to
+ avoid deadlock during which the best-path
+ selection process is deferred, after a peer session was restarted
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Check router status
+ check_router_status(tgen)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ logger.info("Verify EOR Sent after deferral timeout : BGP_GR_TC_11")
+
+ # Configure graceful-restart
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "graceful-restart": {
+ "graceful-restart": True,
+ "select-defer-time": GR_SELECT_DEFER_TIMER,
+ },
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {"dest_link": {"r1": {"graceful-restart": True}}},
+ "r3": {"dest_link": {"r1": {"graceful-restart": True}}},
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {"dest_link": {"r1": {"graceful-restart": True}}},
+ "r3": {"dest_link": {"r1": {"graceful-restart": True}}},
+ }
+ }
+ },
+ },
+ }
+ },
+ "r3": {
+ "bgp": {
+ "graceful-restart": {"disable-eor": True},
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ },
+ }
+ },
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+ clear_bgp(tgen, addr_type, "r1")
+ clear_bgp(tgen, addr_type, "r3")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r3"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying BGP RIB routes received from router R1
+ dut = "r1"
+ input_dict_1 = {key: topo["routers"][key] for key in ["r3"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ logger.info("R1 goes for reload")
+ kill_router_daemons(tgen, "r1", ["bgpd"])
+
+ logger.info("Starting bgpd process")
+ start_router_daemons(tgen, "r1", ["bgpd"])
+ logger.info("R1 is UP Now")
+
+ for addr_type in ADDR_TYPES:
+ # Verify EOR on restarting router
+ result = verify_eor(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r3", expected=False
+ )
+ assert result is not True, (
+ "Testcase " + tc_name + " : Failed \n Error: {}".format(result)
+ )
+
+ logger.info(
+ "Waiting for selection deferral timer({} sec).. ".format(
+ GR_SELECT_DEFER_TIMER + 2
+ )
+ )
+ sleep(GR_SELECT_DEFER_TIMER + 2)
+
+ for addr_type in ADDR_TYPES:
+ # Verifying BGP RIB routes received from router R1
+ input_dict_1 = {key: topo["routers"][key] for key in ["r3"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying EOR on restarting router
+ result = verify_eor(
+ tgen, topo, addr_type, input_dict, dut="r3", peer="r1", expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_BGP_GR_10_p2(request):
+ """
+ Test Objective : Test GR scenarios on helper router by enabling
+ Graceful Restart for multiple address families.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Check router status
+ check_router_status(tgen)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ logger.info(
+ "[Step 1] : Test Setup " "[Helper Mode]R3-----R1[Restart Mode] initialized"
+ )
+
+ # Configure graceful-restart
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r1": {
+ "next_hop_self": True,
+ "graceful-restart": True,
+ "activate": "ipv6",
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r1": {
+ "next_hop_self": True,
+ "graceful-restart": True,
+ "activate": "ipv4",
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ "r3": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "graceful-restart-helper": True,
+ "activate": "ipv6",
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "graceful-restart-helper": True,
+ "activate": "ipv4",
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ }
+
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r3"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying BGP RIB routes
+ dut = "r3"
+ input_topo = {key: topo["routers"][key] for key in ["r1"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_topo)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes before shutting down BGPd daemon
+ result = verify_rib(tgen, addr_type, dut, input_topo)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # verify multi address family
+ result = verify_gr_address_family(
+ tgen, topo, addr_type, "ipv4Unicast", dut="r1"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # verify multi address family
+ result = verify_gr_address_family(
+ tgen, topo, addr_type, "ipv6Unicast", dut="r1"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # verify multi address family
+ result = verify_gr_address_family(
+ tgen, topo, addr_type, "ipv4Unicast", dut="r3"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # verify multi address family
+ result = verify_gr_address_family(
+ tgen, topo, addr_type, "ipv6Unicast", dut="r3"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Kill BGPd daemon on R1
+ kill_router_daemons(tgen, "r1", ["bgpd"])
+
+ for addr_type in ADDR_TYPES:
+ # Verifying BGP RIB routes
+ input_topo = {key: topo["routers"][key] for key in ["r1"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_topo)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes before shutting down BGPd daemon
+ result = verify_rib(tgen, addr_type, dut, input_topo)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Start BGPd daemon on R1
+ start_router_daemons(tgen, "r1", ["bgpd"])
+
+ for addr_type in ADDR_TYPES:
+ # Verifying BGP RIB routes
+ input_topo = {key: topo["routers"][key] for key in ["r1"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_topo)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes before shutting down BGPd daemon
+ result = verify_rib(tgen, addr_type, dut, input_topo)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_BGP_GR_16_p2(request):
+ """
+ Test Objective : Verify BGP-GR feature when restarting node
+ is a transit router for it's iBGP peers.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Check router status
+ check_router_status(tgen)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ logger.info(
+ "[Step 1] : Test Setup " "[Helper Mode]R3-----R1[Restart Mode] initialized"
+ )
+
+ # Configure graceful-restart and timers
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r1": {
+ "graceful-restart": True,
+ "next_hop_self": True,
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r1": {
+ "graceful-restart": True,
+ "next_hop_self": True,
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ "r3": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ }
+
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r3"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ logger.info(
+ "[Step 2] : Test Setup "
+ "[Helper Mode]R3-----R1[Restart Mode]"
+ "--------R6[Helper Mode] initialized"
+ )
+
+ # Configure graceful-restart and timers
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {"dest_link": {"r1": {"graceful-restart": True}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {"dest_link": {"r1": {"graceful-restart": True}}}
+ }
+ }
+ },
+ }
+ }
+ },
+ "r2": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ }
+
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying BGP RIB routes
+ dut = "r3"
+ input_dict_1 = {key: topo["routers"][key] for key in ["r1"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes before shutting down BGPd daemon
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying BGP RIB routes
+ input_dict_2 = {key: topo["routers"][key] for key in ["r2"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes before shutting down BGPd daemon
+ result = verify_rib(tgen, addr_type, dut, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Kill BGPd daemon on R1
+ kill_router_daemons(tgen, "r1", ["bgpd"])
+
+ for addr_type in ADDR_TYPES:
+ # Verifying BGP RIB routes
+ input_dict_1 = {key: topo["routers"][key] for key in ["r1"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes before shutting down BGPd daemon
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying BGP RIB routes
+ input_dict_2 = {key: topo["routers"][key] for key in ["r2"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes before shutting down BGPd daemon
+ result = verify_rib(tgen, addr_type, dut, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Start BGPd daemon on R1
+ start_router_daemons(tgen, "r1", ["bgpd"])
+
+ for addr_type in ADDR_TYPES:
+ # Verifying BGP RIB routes
+ input_dict_1 = {key: topo["routers"][key] for key in ["r1"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes before shutting down BGPd daemon
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying BGP RIB routes
+ input_dict_2 = {key: topo["routers"][key] for key in ["r2"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes before shutting down BGPd daemon
+ result = verify_rib(tgen, addr_type, dut, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_convergence(tgen, topo)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_BGP_GR_18_p1(request):
+ """
+ Test Objective : Verify that GR helper router deletes stale routes
+ received from restarting node, if GR capability is not present in
+ restarting node's OPEN message.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Check router status
+ check_router_status(tgen)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ logger.info(
+ "[Step 1] : Test Setup " "[Helper Mode]R6-----R1[Restart Mode] initialized"
+ )
+
+ # Configure graceful-restart and timers
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r6": {"dest_link": {"r1": {"graceful-restart": True}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r6": {"dest_link": {"r1": {"graceful-restart": True}}}
+ }
+ }
+ },
+ }
+ }
+ },
+ "r6": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r6": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r6": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ }
+
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r6")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r6"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ logger.info(
+ "[Step 2] : Test Setup "
+ "[Helper Mode]R6-----R1[Restart Mode]"
+ "--------R2[Helper Mode] initialized"
+ )
+
+ # Configure graceful-restart and timers
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {"dest_link": {"r1": {"graceful-restart": True}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {"dest_link": {"r1": {"graceful-restart": True}}}
+ }
+ }
+ },
+ }
+ }
+ },
+ "r2": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ }
+
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r2"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying BGP RIB routes
+ dut = "r6"
+ input_dict_1 = {key: topo["routers"][key] for key in ["r1"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes before shutting down BGPd daemon
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying BGP RIB routes
+ dut = "r2"
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes before shutting down BGPd daemon
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Kill BGPd daemon on R1
+ kill_router_daemons(tgen, "r1", ["bgpd"])
+
+ logger.info("[Step 3] : Configure R1 to prevent sending EOR")
+
+ # Modify graceful-restart config to prevent sending EOR
+ input_dict_3 = {"r1": {"bgp": {"graceful-restart": {"disable-eor": True}}}}
+
+ result = modify_bgp_config_when_bgpd_down(tgen, topo, input_dict_3)
+
+ # Modify configuration to delete routes
+ network = {"ipv4": "101.0.20.1/32", "ipv6": "1::1/128"}
+ for addr_type in ADDR_TYPES:
+ input_dict_3 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": network[addr_type],
+ "no_of_network": 5,
+ "delete": True,
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = modify_bgp_config_when_bgpd_down(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Modify graceful-restart config
+ input_dict_3 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1": {"graceful-restart-disable": True}
+ }
+ },
+ "r6": {
+ "dest_link": {
+ "r1": {"graceful-restart-disable": True}
+ }
+ },
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1": {"graceful-restart-disable": True}
+ }
+ },
+ "r6": {
+ "dest_link": {
+ "r1": {"graceful-restart-disable": True}
+ }
+ },
+ }
+ }
+ },
+ }
+ }
+ }
+ }
+
+ result = modify_bgp_config_when_bgpd_down(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result)
+
+ logger.info("[Step 4] : Bring up the BGPd daemon on R1 for 30" " seconds..")
+
+ # Start BGPd daemon on R1
+ start_router_daemons(tgen, "r1", ["bgpd"])
+
+ for addr_type in ADDR_TYPES:
+ # Verifying BGP RIB routes
+ dut = "r6"
+ input_dict_1 = {key: topo["routers"][key] for key in ["r1"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+ logger.info(" Expected behavior: {}".format(result))
+
+ # Verifying RIB routes before shutting down BGPd daemon
+ result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+ logger.info(" Expected behavior: {}".format(result))
+
+ # Verifying BGP RIB routes
+ dut = "r2"
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+ logger.info(" Expected behavior: {}".format(result))
+
+ # Verifying RIB routes before shutting down BGPd daemon
+ result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+ logger.info(" Expected behavior: {}".format(result))
+
+ write_test_footer(tc_name)
+
+
+def test_BGP_GR_26_p2(request):
+ """
+ Test Objective : Test GR scenarios on helper router by enabling
+ Graceful Restart for multiple address families.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Check router status
+ check_router_status(tgen)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ logger.info(
+ "[Step 1] : Test Setup " "[Helper Mode]R3-----R1[Restart Mode] initialized"
+ )
+
+ # Configure graceful-restart
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r1": {
+ "graceful-restart": True,
+ "next_hop_self": True,
+ "activate": "ipv6",
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r1": {
+ "graceful-restart": True,
+ "next_hop_self": True,
+ "activate": "ipv4",
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ "r3": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "graceful-restart-helper": True,
+ "activate": "ipv6",
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {
+ "graceful-restart-helper": True,
+ "activate": "ipv4",
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ }
+
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r3", peer="r1"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying BGP RIB routes
+ dut = "r3"
+ input_topo = {key: topo["routers"][key] for key in ["r1"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_topo)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes before shutting down BGPd daemon
+ result = verify_rib(tgen, addr_type, dut, input_topo)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Kill BGPd daemon on R1
+ kill_router_daemons(tgen, "r1", ["bgpd"])
+
+ for addr_type in ADDR_TYPES:
+ # Verifying BGP RIB routes
+ input_topo = {key: topo["routers"][key] for key in ["r1"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_topo)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes before shutting down BGPd daemon
+ result = verify_rib(tgen, addr_type, dut, input_topo)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Start BGPd daemon on R1
+ start_router_daemons(tgen, "r1", ["bgpd"])
+
+ for addr_type in ADDR_TYPES:
+ # Verifying BGP RIB routes
+ input_topo = {key: topo["routers"][key] for key in ["r1"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_topo)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes before shutting down BGPd daemon
+ result = verify_rib(tgen, addr_type, dut, input_topo)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # verify multi address family
+ result = verify_gr_address_family(
+ tgen, topo, addr_type, "ipv4Unicast", dut="r1"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # verify multi address family
+ result = verify_gr_address_family(
+ tgen, topo, addr_type, "ipv6Unicast", dut="r1"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # verify multi address family
+ result = verify_gr_address_family(
+ tgen, topo, addr_type, "ipv4Unicast", dut="r3"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # verify multi address family
+ result = verify_gr_address_family(
+ tgen, topo, addr_type, "ipv6Unicast", dut="r3"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_BGP_GR_chaos_28_p1(request):
+ """
+ Test Objective : Verify if helper node goes down before restarting
+ node comes up online, helper node sets the R-bit to avoid dead-lock
+ till SDT expiry.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Check router status
+ check_router_status(tgen)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ logger.info(
+ "Test Case: test_BGP_GR_chaos_28 :"
+ "[Helper Mode]R3-----R1[Restart Mode] initialized"
+ )
+
+ # Configure graceful-restart
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {"dest_link": {"r1": {"graceful-restart": True}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {"dest_link": {"r1": {"graceful-restart": True}}}
+ }
+ }
+ },
+ }
+ }
+ },
+ "r3": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ }
+
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r3"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ logger.info("[Step 1] : Kill BGPd daemon on R1..")
+
+ # Kill BGPd daemon on R1
+ kill_router_daemons(tgen, "r1", ["bgpd"])
+
+ logger.info("[Step 2] : Kill BGPd daemon on R3..")
+
+ # Kill BGPd daemon on R3
+ kill_router_daemons(tgen, "r3", ["bgpd"])
+
+ logger.info("[Step 3] : Start BGPd daemon on R1..")
+
+ # Start BGPd daemon on R1
+ start_router_daemons(tgen, "r1", ["bgpd"])
+
+ logger.info("[Step 4] : Start BGPd daemon on R3..")
+
+ # Start BGPd daemon on R3
+ start_router_daemons(tgen, "r3", ["bgpd"])
+
+ # Verify r_bit
+ for addr_type in ADDR_TYPES:
+ result = verify_r_bit(tgen, topo, addr_type, input_dict, dut="r3", peer="r1")
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_BGP_GR_chaos_29_p1(request):
+ """
+ Test Objective : Change timers on the fly, and
+ verify if it takes immediate effect.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Check router status
+ check_router_status(tgen)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ logger.info(
+ " Test Case : BGP_GR_UTP_29"
+ " BGP GR [Helper Mode]R3-----R1[Restart Mode]"
+ " and [restart-time 150]R1 initialized"
+ )
+
+ # Configure graceful-restart and timers
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "graceful-restart": {"timer": {"restart-time": GR_RESTART_TIMER}},
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {"dest_link": {"r1": {"graceful-restart": True}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {"dest_link": {"r1": {"graceful-restart": True}}}
+ }
+ }
+ },
+ },
+ }
+ },
+ "r3": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ }
+
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r3"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verify graceful-restart timers
+ input_dict_2 = {
+ "r1": {
+ "bgp": {
+ "graceful-restart": {"timer": {"restart-time": GR_RESTART_TIMER + 5}}
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "r1": {
+ "bgp": {
+ "graceful-restart": {"timer": {"restart-time": GR_RESTART_TIMER}}
+ }
+ }
+ }
+
+ result = verify_graceful_restart_timers(
+ tgen, topo, addr_type, input_dict_2, dut="r3", peer="r1"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ # Verifying BGP RIB routes before shutting down BGPd daemon
+ dut = "r3"
+ input_dict = {key: topo["routers"][key] for key in ["r1"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes before shutting down BGPd daemon
+ result = verify_rib(tgen, addr_type, dut, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ logger.info("[Step 2] : Kill BGPd daemon on R1..")
+
+ # Kill BGPd daemon on R1
+ kill_router_daemons(tgen, "r1", ["bgpd"])
+
+ # Waiting for 120 sec
+ logger.info("[Step 3] : Wait for {} seconds..".format(GR_RESTART_TIMER))
+
+ # Waiting for 120 sec
+ sleep(GR_RESTART_TIMER)
+
+ for addr_type in ADDR_TYPES:
+ # Verifying BGP RIB routes before shutting down BGPd daemon
+ input_dict = {key: topo["routers"][key] for key in ["r1"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict, expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+ logger.info(" Expected behavior: {}".format(result))
+
+ # Verifying RIB routes before shutting down BGPd daemon
+ result = verify_rib(tgen, addr_type, dut, input_dict, expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+ logger.info(" Expected behavior: {}".format(result))
+
+ logger.info("[Step 4] : Start BGPd daemon on R1..")
+
+ # Start BGPd daemon on R1
+ start_router_daemons(tgen, "r1", ["bgpd"])
+
+ write_test_footer(tc_name)
+
+
+def test_BGP_GR_chaos_33_p1(request):
+ """
+ Test Objective : Helper router receives same prefixes from two
+ different routers (GR-restarting and GR-disabled). Keeps the
+ stale entry only for GR-restarting node(next-hop is correct).
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Check router status
+ check_router_status(tgen)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ logger.info(
+ " Test Case : test_BGP_GR_chaos_33 "
+ "BGP GR "
+ "[Restart Mode]R1--R3[Helper Mode]--R4[Disabled Mode]"
+ )
+
+ # Configure graceful-restart
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {"dest_link": {"r1": {"graceful-restart": True}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {"dest_link": {"r1": {"graceful-restart": True}}}
+ }
+ }
+ },
+ }
+ }
+ },
+ "r3": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ "r4": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r4": {"graceful-restart-disable": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r4": {"graceful-restart-disable": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ }
+
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r3"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ logger.info("[Step 2] : Advertise same networks from R1 and R4..")
+
+ # Api call to delete advertised networks
+ input_dict_2 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "advertise_networks": [
+ {"network": "200.0.20.1/32", "no_of_network": 2,}
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "advertise_networks": [
+ {"network": "2001::1/128", "no_of_network": 2}
+ ]
+ }
+ },
+ }
+ }
+ },
+ "r4": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "advertise_networks": [
+ {"network": "200.0.20.1/32", "no_of_network": 2}
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "advertise_networks": [
+ {"network": "2001::1/128", "no_of_network": 2}
+ ]
+ }
+ },
+ }
+ }
+ },
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+ # Verifying RIB routes
+ dut = "r3"
+ peer1 = "r1"
+ peer2 = "r4"
+ intf1 = topo["routers"][peer1]["links"][dut]["interface"]
+ intf2 = topo["routers"][peer2]["links"][dut]["interface"]
+
+ if addr_type == "ipv4":
+ next_hop_4 = NEXT_HOP_4
+ result = verify_rib(tgen, addr_type, dut, input_dict_2, next_hop_4)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ if addr_type == "ipv6":
+ if "link_local" in PREFERRED_NEXT_HOP:
+ next_hop1 = get_frr_ipv6_linklocal(tgen, peer1, intf=intf1)
+ next_hop2 = get_frr_ipv6_linklocal(tgen, peer2, intf=intf2)
+
+ next_hop_6 = [next_hop1, next_hop2]
+ else:
+ next_hop_6 = NEXT_HOP_6
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2, next_hop_6)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ logger.info("[Step 3] : Kill BGPd daemon on R1 and R4..")
+
+ # Kill BGPd daemon on R1
+ kill_router_daemons(tgen, "r1", ["bgpd"])
+
+ # Kill BGPd daemon on R4
+ kill_router_daemons(tgen, "r4", ["bgpd"])
+
+ for addr_type in ADDR_TYPES:
+ # Verifying RIB routes
+ next_hop_6 = ["fd00:0:0:1::1"]
+ if addr_type == "ipv4":
+ next_hop_4 = NEXT_HOP_4[0]
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2, next_hop_4)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ if addr_type == "ipv6":
+ if "link_local" in PREFERRED_NEXT_HOP:
+ next_hop_6 = get_frr_ipv6_linklocal(tgen, peer1, intf=intf1)
+ else:
+ next_hop_6 = NEXT_HOP_6[0]
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2, next_hop_6)
+
+ # Verifying RIB routes
+ if addr_type == "ipv4":
+ next_hop_4 = NEXT_HOP_4[1]
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_2, next_hop_4, expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+ logger.info(" Expected behavior: {}".format(result))
+
+ if addr_type == "ipv6":
+ if "link_local" in PREFERRED_NEXT_HOP:
+ next_hop_6 = get_frr_ipv6_linklocal(tgen, peer2, intf=intf2)
+ else:
+ next_hop_6 = NEXT_HOP_6[1]
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2, next_hop_6)
+
+ logger.info("[Step 4] : Start BGPd daemon on R1 and R4..")
+
+ # Start BGPd daemon on R1
+ start_router_daemons(tgen, "r1", ["bgpd"])
+
+ # Start BGPd daemon on R4
+ start_router_daemons(tgen, "r4", ["bgpd"])
+
+ write_test_footer(tc_name)
+
+
+def test_BGP_GR_chaos_34_2_p1(request):
+ """
+ Test Objective : Restarting node doesn't preserve the forwarding
+ state verify the behaviour on helper node, if it still keeps the
+ stale routes.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Check router status
+ check_router_status(tgen)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ logger.info(
+ " Test Case : test_BGP_GR_chaos_34 "
+ "BGP GR "
+ "[Restart Mode]R1---R3[Helper Mode]"
+ )
+
+ logger.info("[Step 1] : Configure restarting" " router R1 to prevent ")
+ logger.info("[Step 2] : Reset the session" " between R1 and R3..")
+
+ # Configure graceful-restart
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "graceful-restart": {"preserve-fw-state": True, "disable-eor": True},
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {"dest_link": {"r1": {"graceful-restart": True}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {"dest_link": {"r1": {"graceful-restart": True}}}
+ }
+ }
+ },
+ },
+ }
+ },
+ "r3": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ }
+
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r3"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verify f-bit before killing BGPd daemon
+ result = verify_f_bit(tgen, topo, addr_type, input_dict, "r3", "r1")
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying BGP RIB routes after starting BGPd daemon
+ dut = "r3"
+ input_dict_1 = {key: topo["routers"][key] for key in ["r1"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ logger.info("[Step 3] : Kill BGPd daemon on R1..")
+
+ # Kill BGPd daemon on R1
+ kill_router_daemons(tgen, "r1", ["bgpd"])
+
+ logger.info("[Step 4] : Withdraw/delete the prefixes " "originated from R1..")
+
+ # Api call to delete advertised networks
+ network = {"ipv4": "101.0.20.1/32", "ipv6": "1::1/128"}
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": network[addr_type],
+ "no_of_network": 5,
+ "delete": True,
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = modify_bgp_config_when_bgpd_down(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ logger.info("[Step 5] : Remove the CLI from R1's config to " "set the F-bit..")
+
+ # Modify graceful-restart config not to set f-bit
+ # and write to /etc/frr
+ input_dict_2 = {"r1": {"bgp": {"graceful-restart": {"preserve-fw-state": False}}}}
+
+ result = modify_bgp_config_when_bgpd_down(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result)
+
+ logger.info("[Step 6] : Bring up the BGPd daemon on R1 again..")
+
+ # Start BGPd daemon on R1
+ start_router_daemons(tgen, "r1", ["bgpd"])
+
+ for addr_type in ADDR_TYPES:
+ # Verify f-bit after starting BGPd daemon
+ result = verify_f_bit(
+ tgen, topo, addr_type, input_dict, "r3", "r1", expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+ logger.info(" Expected behavior: {}".format(result))
+
+ # Verifying BGP RIB routes after starting BGPd daemon
+ input_dict_1 = {key: topo["routers"][key] for key in ["r1"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+ logger.info(" Expected behavior: {}".format(result))
+
+ # Verifying RIB routes
+ result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+ logger.info(" Expected behavior: {}".format(result))
+
+ write_test_footer(tc_name)
+
+
+def test_BGP_GR_chaos_34_1_p1(request):
+ """
+ Test Objective : Restarting node doesn't preserve forwarding
+ state, helper router should not keep the stale entries.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Check router status
+ check_router_status(tgen)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ logger.info(
+ " Test Case : test_BGP_GR_chaos_31 "
+ "BGP GR "
+ "[Restart Mode]R1---R3[Helper Mode]"
+ )
+
+ # Configure graceful-restart
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "graceful-restart": {
+ "preserve-fw-state": True,
+ "timer": {"restart-time": GR_RESTART_TIMER},
+ },
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {"dest_link": {"r1": {"graceful-restart": True}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {"dest_link": {"r1": {"graceful-restart": True}}}
+ }
+ }
+ },
+ },
+ }
+ },
+ "r3": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ }
+
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r3"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying BGP RIB routes after starting BGPd daemon
+ dut = "r3"
+ input_dict_1 = {key: topo["routers"][key] for key in ["r1"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ logger.info(
+ "[Step 1] : Remove the preserve-fw-state command"
+ " from restarting node R1's config"
+ )
+
+ # Configure graceful-restart to set f-bit as False
+ input_dict_2 = {"r1": {"bgp": {"graceful-restart": {"preserve-fw-state": False}}}}
+
+ result = create_router_bgp(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ logger.info("[Step 2] : Reset the session between R1 and R3..")
+
+ # Reset sessions
+ for addr_type in ADDR_TYPES:
+ clear_bgp(tgen, addr_type, "r1")
+
+ for addr_type in ADDR_TYPES:
+ # Verify f-bit after starting BGPd daemon
+ result = verify_f_bit(
+ tgen, topo, addr_type, input_dict_2, "r3", "r1", expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+ logger.info(" Expected behavior: {}".format(result))
+
+ logger.info("[Step 3] : Kill BGPd daemon on R1..")
+
+ # Kill BGPd daemon on R1
+ kill_router_daemons(tgen, "r1", ["bgpd"])
+
+ # Waiting for 120 sec
+ logger.info("Waiting for {} sec..".format(GR_RESTART_TIMER))
+ sleep(GR_RESTART_TIMER)
+
+ for addr_type in ADDR_TYPES:
+ # Verifying BGP RIB routes
+ input_dict = {key: topo["routers"][key] for key in ["r1"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict, expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+ logger.info(" Expected behavior: {}".format(result))
+
+ # Verifying RIB routes
+ result = verify_rib(tgen, addr_type, dut, input_dict, expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+ logger.info(" Expected behavior: {}".format(result))
+
+ # Start BGPd daemon on R1
+ start_router_daemons(tgen, "r1", ["bgpd"])
+
+ write_test_footer(tc_name)
+
+
+def test_BGP_GR_chaos_32_p1(request):
+ """
+ Test Objective : Restarting node is connected to multiple helper
+ nodes, one of them doesn't send EOR to restarting router. Verify
+ that only after SDT restarting node send EOR to all helper peers
+ excluding the prefixes originated by faulty router.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Check router status
+ check_router_status(tgen)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ logger.info(
+ " Test Case : test_BGP_GR_chaos_32 "
+ "BGP GR "
+ "[Restart Mode]R1---R3&R5[Helper Mode]"
+ )
+
+ logger.info(
+ "[Step 1] : Change the mode on R1 be a restarting" " node on global level"
+ )
+
+ # Configure graceful-restart
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "graceful-restart": {"graceful-restart": True},
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {"dest_link": {"r1": {"next_hop_self": True}}},
+ "r5": {"dest_link": {"r1": {"graceful-restart": True}}},
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {"dest_link": {"r1": {"next_hop_self": True}}},
+ "r5": {"dest_link": {"r1": {"graceful-restart": True}}},
+ }
+ }
+ },
+ },
+ }
+ },
+ "r5": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r5": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r5": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ }
+
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r5")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r5"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying BGP RIB routes after starting BGPd daemon
+ dut = "r3"
+ input_dict_1 = {key: topo["routers"][key] for key in ["r5"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ logger.info("[Step 2] : Kill BGPd daemon on R1..")
+ # Kill BGPd daemon on R1
+ kill_router_daemons(tgen, "r1", ["bgpd"])
+
+ logger.info("[Step 3] : Withdraw all the advertised prefixes from R5")
+
+ # Api call to delete advertised networks
+ network = {"ipv4": "105.0.20.1/32", "ipv6": "5::1/128"}
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "r5": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": network[addr_type],
+ "no_of_network": 5,
+ "delete": True,
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ logger.info(
+ "[Step 4] : Stop the helper router R5 from sending EOR" " message using CLI"
+ )
+
+ # Modify graceful-restart config to prevent sending EOR
+ input_dict_3 = {"r5": {"bgp": {"graceful-restart": {"disable-eor": True}}}}
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ logger.info("[Step 5] : Bring up the BGPd daemon on R1..")
+
+ # Start BGPd daemon on R1
+ start_router_daemons(tgen, "r1", ["bgpd"])
+
+ for addr_type in ADDR_TYPES:
+ # Verify EOR is disabled
+ result = verify_eor(
+ tgen, topo, addr_type, input_dict_3, dut="r5", peer="r1", expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+ logger.info(" Expected behavior: {}".format(result))
+
+ # Verifying BGP RIB routes after starting BGPd daemon
+ input_dict_1 = {key: topo["routers"][key] for key in ["r5"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+ logger.info(" Expected behavior: {}".format(result))
+
+ # Verifying RIB routes
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+ logger.info(" Expected behavior: {}".format(result))
+
+ write_test_footer(tc_name)
+
+
+def test_BGP_GR_chaos_37_p1(request):
+ """
+ Test Objective : Verify if helper node restarts before sending the
+ EOR message, restarting node doesn't wait until stale path timer
+ expiry to do the best path selection and sends an EOR
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Check router status
+ check_router_status(tgen)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ logger.info(
+ " Test Case : test_BGP_GR_chaos_37 "
+ "BGP GR "
+ "[Restart Mode]R1---R3[Helper Mode]"
+ )
+
+ logger.info(
+ "[Step 1] : Configure restarting router R3 to prevent " "sending an EOR.."
+ )
+
+ logger.info("[Step 2] : Reset the session between R3 and R1..")
+
+ # Configure graceful-restart
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {"dest_link": {"r1": {"graceful-restart": True}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {"dest_link": {"r1": {"graceful-restart": True}}}
+ }
+ }
+ },
+ }
+ }
+ },
+ "r3": {
+ "bgp": {
+ "graceful-restart": {"disable-eor": True},
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ },
+ }
+ },
+ }
+
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r3"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verify EOR is disabled
+ result = verify_eor(
+ tgen, topo, addr_type, input_dict, dut="r3", peer="r1", expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+ logger.info(" Expected behavior: {}".format(result))
+
+ # Verifying BGP RIB routes after starting BGPd daemon
+ dut = "r1"
+ input_dict_1 = {key: topo["routers"][key] for key in ["r3"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ logger.info("[Step 3] : Kill BGPd daemon on R1..")
+
+ # Kill BGPd daemon on R1
+ kill_router_daemons(tgen, "r1", ["bgpd"])
+
+ logger.info("[Step 4] : Start BGPd daemon on R1..")
+
+ # Start BGPd daemon on R1
+ start_router_daemons(tgen, "r1", ["bgpd"])
+
+ logger.info("[Step 5] : Kill BGPd daemon on R3..")
+
+ # Kill BGPd daemon on R3
+ kill_router_daemons(tgen, "r3", ["bgpd"])
+
+ # Modify graceful-restart config to prevent sending EOR
+ input_dict_2 = {"r3": {"bgp": {"graceful-restart": {"disable-eor": True}}}}
+
+ result = modify_bgp_config_when_bgpd_down(tgen, topo, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result)
+
+ logger.info("[Step 6] : Start BGPd daemon on R3..")
+
+ # Start BGPd daemon on R3
+ start_router_daemons(tgen, "r3", ["bgpd"])
+
+ for addr_type in ADDR_TYPES:
+ # Verify r_bit
+ result = verify_r_bit(tgen, topo, addr_type, input_dict, dut="r1", peer="r3")
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes
+ input_dict_1 = {key: topo["routers"][key] for key in ["r3"]}
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verify EOR is send from R1 to R3
+ input_dict_3 = {"r1": {"bgp": {"graceful-restart": {"disable-eor": True}}}}
+
+ result = verify_eor(
+ tgen, topo, addr_type, input_dict_3, dut="r1", peer="r3", expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_BGP_GR_chaos_30_p1(request):
+ """
+ Test Objective : Restarting node removes stale routes from Zebra
+ after receiving an EOR from helper router.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ # Check router status
+ check_router_status(tgen)
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ reset_config_on_routers(tgen)
+
+ logger.info(
+ " Test Case : test_BGP_GR_chaos_30 "
+ "BGP GR [Helper Mode]R3-----R1[Restart Mode] "
+ )
+
+ # Configure graceful-restart and timers
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "graceful-restart": {"preserve-fw-state": True},
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {"dest_link": {"r1": {"graceful-restart": True}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {"dest_link": {"r1": {"graceful-restart": True}}}
+ }
+ }
+ },
+ },
+ }
+ },
+ "r3": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r3": {"graceful-restart-helper": True}
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ }
+
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r1", peer="r3"
+ )
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ # Verifying BGP RIB routes before shutting down BGPd daemon
+ dut = "r1"
+ input_dict = {key: topo["routers"][key] for key in ["r3"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes before shutting down BGPd daemon
+ result = verify_rib(tgen, addr_type, dut, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ logger.info("[Step 2] : Kill BGPd daemon on R1..")
+
+ # Kill BGPd daemon on R1
+ kill_router_daemons(tgen, "r1", ["bgpd"])
+
+ logger.info("[Step 3] : Withdraw advertised prefixes from R3...")
+
+ # Api call to delete advertised networks
+ network = {"ipv4": "103.0.20.1/32", "ipv6": "3::1/128"}
+ for addr_type in ADDR_TYPES:
+ input_dict = {
+ "r3": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": network[addr_type],
+ "no_of_network": 5,
+ "delete": True,
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ logger.info("[Step 4] : Start BGPd daemon on R1..")
+
+ # Start BGPd daemon on R1
+ start_router_daemons(tgen, "r1", ["bgpd"])
+
+ for addr_type in ADDR_TYPES:
+ # Verifying BGP RIB routes before shutting down BGPd daemon
+ input_dict = {key: topo["routers"][key] for key in ["r3"]}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict, expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+ logger.info(" Expected behavior: {}".format(result))
+
+ # Verifying RIB routes before shutting down BGPd daemon
+ result = verify_rib(tgen, addr_type, dut, input_dict, expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+ logger.info(" Expected behavior: {}".format(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_multi_vrf_topo1/bgp_multi_vrf_topo1.json b/tests/topotests/bgp_multi_vrf_topo1/bgp_multi_vrf_topo1.json
new file mode 100644
index 0000000000..327744d3a1
--- /dev/null
+++ b/tests/topotests/bgp_multi_vrf_topo1/bgp_multi_vrf_topo1.json
@@ -0,0 +1,884 @@
+{
+ "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": {
+ "red1": {
+ "links": {
+ "r1-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "r1-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"}
+ },
+ "vrfs":[
+ {
+ "name": "RED_A",
+ "id": "1"
+ },
+ {
+ "name": "RED_B",
+ "id": "2"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "500",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "500",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link2": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "blue1": {
+ "links": {
+ "r1-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_A"},
+ "r1-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"}
+ },
+ "vrfs":[
+ {
+ "name": "BLUE_A",
+ "id": "1"
+ },
+ {
+ "name": "BLUE_B",
+ "id": "2"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "800",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "blue1-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "blue1-link1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "800",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "blue1-link2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "blue1-link2": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "r1": {
+ "links": {
+ "red1-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "red1-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"},
+ "blue1-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_A"},
+ "blue1-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"},
+ "r2-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "r2-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"},
+ "r2-link3": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_A"},
+ "r2-link4": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"}
+ },
+ "vrfs":[
+ {
+ "name": "RED_A",
+ "id": "1"
+ },
+ {
+ "name": "RED_B",
+ "id": "2"
+ },
+ {
+ "name": "BLUE_A",
+ "id": "3"
+ },
+ {
+ "name": "BLUE_B",
+ "id": "4"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "100",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link1": {}
+ }
+ },
+ "r2": {
+ "dest_link": {
+ "r1-link1":
+ { "next_hop_self": true }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link1": {}
+ }
+ },
+ "r2": {
+ "dest_link": {
+ "r1-link1":
+ { "next_hop_self": true }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link2": {}
+ }
+ },
+ "r2": {
+ "dest_link": {
+ "r1-link2":
+ { "next_hop_self": true }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link2": {}
+ }
+ },
+ "r2": {
+ "dest_link": {
+ "r1-link2":
+ { "next_hop_self": true }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link1": {}
+ }
+ },
+ "r2": {
+ "dest_link": {
+ "r1-link3":
+ { "next_hop_self": true }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link1": {}
+ }
+ },
+ "r2": {
+ "dest_link": {
+ "r1-link3":
+ { "next_hop_self": true }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link2": {}
+ }
+ },
+ "r2": {
+ "dest_link": {
+ "r1-link4":
+ { "next_hop_self": true }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link2": {}
+ }
+ },
+ "r2": {
+ "dest_link": {
+ "r1-link4":
+ { "next_hop_self": true }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "r2": {
+ "links": {
+ "r1-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "r1-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"},
+ "r1-link3": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_A"},
+ "r1-link4": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"},
+ "r3-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "r3-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"},
+ "r3-link3": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_A"},
+ "r3-link4": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"}
+ },
+ "vrfs":[
+ {
+ "name": "RED_A",
+ "id": "1"
+ },
+ {
+ "name": "RED_B",
+ "id": "2"
+ },
+ {
+ "name": "BLUE_A",
+ "id": "3"
+ },
+ {
+ "name": "BLUE_B",
+ "id": "4"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "100",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link2": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link2": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link2": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link3": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link3": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link3": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link3": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link4": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link4": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link4": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link4": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "r3": {
+ "links": {
+ "r2-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "r2-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"},
+ "r2-link3": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_A"},
+ "r2-link4": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"},
+ "red2-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "red2-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"},
+ "blue2-link1": {"ipv4": "auto", "ipv6": "autor3", "vrf": "BLUE_A"},
+ "blue2-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"}
+ },
+ "vrfs":[
+ {
+ "name": "RED_A",
+ "id": "1"
+ },
+ {
+ "name": "RED_B",
+ "id": "2"
+ },
+ {
+ "name": "BLUE_A",
+ "id": "3"
+ },
+ {
+ "name": "BLUE_B",
+ "id": "4"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "200",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {}
+ }
+ },
+ "red2": {
+ "dest_link": {
+ "r3-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {}
+ }
+ },
+ "red2": {
+ "dest_link": {
+ "r3-link1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "200",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link2": {}
+ }
+ },
+ "red2": {
+ "dest_link": {
+ "r3-link2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link2": {}
+ }
+ },
+ "red2": {
+ "dest_link": {
+ "r3-link2": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "200",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link3": {}
+ }
+ },
+ "blue2": {
+ "dest_link": {
+ "r3-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link3": {}
+ }
+ },
+ "blue2": {
+ "dest_link": {
+ "r3-link1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "200",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link4": {}
+ }
+ },
+ "blue2": {
+ "dest_link": {
+ "r3-link2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link4": {}
+ }
+ },
+ "blue2": {
+ "dest_link": {
+ "r3-link2": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "red2": {
+ "links": {
+ "r3-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "r3-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"}
+ },
+ "vrfs":[
+ {
+ "name": "RED_A",
+ "id": "1"
+ },
+ {
+ "name": "RED_B",
+ "id": "2"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "500",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "red2-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "red2-link1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "500",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "red2-link2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "red2-link2": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "blue2": {
+ "links": {
+ "r3-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_A"},
+ "r3-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"}
+ },
+ "vrfs":[
+ {
+ "name": "BLUE_A",
+ "id": "1"
+ },
+ {
+ "name": "BLUE_B",
+ "id": "2"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "800",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "blue2-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "blue2-link1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "800",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "blue2-link2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "blue2-link2": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+ }
+}
diff --git a/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py b/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py
new file mode 100755
index 0000000000..aabce04f24
--- /dev/null
+++ b/tests/topotests/bgp_multi_vrf_topo1/test_bgp_multi_vrf_topo1.py
@@ -0,0 +1,6300 @@
+#!/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:
+
+FUNC_1:
+ Within each VRF, each address must be unambiguous on DUT.
+FUNC_2:
+ Different VRFs can have ambiguous/overlapping
+ addresses on DUT.
+FUNC_3:
+ Create static routes(IPv4+IPv6) associated to specific VRFs
+ and verify on DUT that same prefixes are present in corresponding
+ routing table.
+FUNC_4_&_5:
+ Each VRF should be mapped with a unique VLAN on DUT
+ for traffic segregation, when using a single physical interface.
+FUNC_6:
+ Advertise same set of prefixes from different VRFs
+ and verify on remote router that these prefixes are not
+ leaking to each other
+FUNC_7:
+ Redistribute Static routes and verify on remote routers
+ that routes are advertised within specific VRF instance, which
+ those static routes belong to.
+FUNC_8:
+ Test end to end traffic isolation based on VRF tables.
+FUNC_9:
+ Use static routes for inter-vrf communication
+ (route-leaking) on DUT.
+FUNC_10:
+ Verify intra-vrf and inter-vrf communication between
+ iBGP peers.
+FUNC_11:
+ Verify intra-vrf and inter-vrf communication
+ between eBGP peers.
+FUNC_12_a:
+ Configure route-maps within a VRF, to alter BGP attributes.
+ Verify that route-map doesn't affect any other VRF instances'
+ routing on DUT.
+FUNC_12_b:
+ Configure route-maps within a VRF, to alter BGP attributes.
+ Verify that route-map doesn't affect any other VRF instances'
+ routing on DUT.
+FUNC_12_c:
+ Configure route-maps within a VRF, to alter BGP attributes.
+ Verify that route-map doesn't affect any other VRF instances'
+ routing on DUT.
+FUNC_12_d:
+ Configure route-maps within a VRF, to alter BGP attributes.
+ Verify that route-map doesn't affect any other VRF instances'
+ routing on DUT.
+FUNC_12_e:
+ Configure route-maps within a VRF, to alter BGP attributes.
+ Verify that route-map doesn't affect any other VRF instances'
+ routing on DUT.
+FUNC_12_f:
+ Configure route-maps within a VRF, to alter BGP attributes.
+ Verify that route-map doesn't affect any other VRF instances'
+ routing on DUT.
+FUNC_13:
+ Configure a route-map on DUT to match traffic based
+ on a VRF interfaces.
+FUNC_14:
+ Test VRF-lite with Static+BGP originated routes.
+FUNC_15:
+ Configure prefix-lists on DUT and apply to BGP peers to
+ permit/deny prefixes.
+FUNC_16_1:
+ Configure a route-map on DUT to match traffic based various
+ match/set causes.
+FUNC_16_2:
+ Configure a route-map on DUT to match traffic based various
+ match/set causes.
+FUNC_16_3:
+ Configure a route-map on DUT to match traffic based various
+ match/set causes.
+"""
+
+import os
+import sys
+import json
+import time
+import pytest
+from copy import deepcopy
+
+# 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 mininet.topo import Topo
+
+from lib.common_config import (
+ step,
+ verify_rib,
+ start_topology,
+ write_test_header,
+ check_address_types,
+ write_test_footer,
+ reset_config_on_routers,
+ create_route_maps,
+ create_static_routes,
+ create_prefix_lists,
+ create_interface_in_kernel,
+ kill_mininet_routers_process,
+ create_bgp_community_lists,
+ check_router_status,
+ apply_raw_config,
+)
+
+from lib.topolog import logger
+from lib.bgp import (
+ clear_bgp,
+ verify_bgp_rib,
+ create_router_bgp,
+ verify_bgp_community,
+ verify_bgp_convergence,
+ verify_best_path_as_per_bgp_attribute,
+)
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/bgp_multi_vrf_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": "1.1.1.1/32", "ipv6": "1::1/128"}
+NETWORK1_2 = {"ipv4": "1.1.1.2/32", "ipv6": "1::2/128"}
+NETWORK2_1 = {"ipv4": "2.1.1.1/32", "ipv6": "2::1/128"}
+NETWORK2_2 = {"ipv4": "2.1.1.2/32", "ipv6": "2::2/128"}
+NETWORK3_1 = {"ipv4": "3.1.1.1/32", "ipv6": "3::1/128"}
+NETWORK3_2 = {"ipv4": "3.1.1.2/32", "ipv6": "3::2/128"}
+NETWORK4_1 = {"ipv4": "4.1.1.1/32", "ipv6": "4::1/128"}
+NETWORK4_2 = {"ipv4": "4.1.1.2/32", "ipv6": "4::2/128"}
+NETWORK5_1 = {"ipv4": "5.1.1.1/32", "ipv6": "5::1/128"}
+NETWORK5_2 = {"ipv4": "5.1.1.2/32", "ipv6": "5::2/128"}
+NETWORK6_1 = {"ipv4": "6.1.1.1/32", "ipv6": "6::1/128"}
+NETWORK6_2 = {"ipv4": "6.1.1.2/32", "ipv6": "6::2/128"}
+NETWORK7_1 = {"ipv4": "7.1.1.1/32", "ipv6": "7::1/128"}
+NETWORK7_2 = {"ipv4": "7.1.1.2/32", "ipv6": "7::2/128"}
+NETWORK8_1 = {"ipv4": "8.1.1.1/32", "ipv6": "8::1/128"}
+NETWORK8_2 = {"ipv4": "8.1.1.2/32", "ipv6": "8::2/128"}
+
+NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"}
+
+LOOPBACK_1 = {
+ "ipv4": "10.10.10.10/32",
+ "ipv6": "10::10:10/128",
+ "ipv4_mask": "255.255.255.255",
+ "ipv6_mask": None,
+}
+LOOPBACK_2 = {
+ "ipv4": "20.20.20.20/32",
+ "ipv6": "20::20:20/128",
+ "ipv4_mask": "255.255.255.255",
+ "ipv6_mask": None,
+}
+
+
+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
+ """
+
+ 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.
+
+ # Kill stale mininet routers and process
+ kill_mininet_routers_process(tgen)
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start deamons and then start routers
+ start_topology(tgen)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ 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_address_unambiguous_within_each_vrf_p0(request):
+ """
+ FUNC_1:
+ Within each VRF, each address must be unambiguous on DUT.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step("Configure a set of static routes(IPv4+IPv6) in " "RED_A on router RED-1")
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": NETWORK1_1[addr_type],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Configure the same static routes(IPv4+IPv6) with a TAG value"
+ "of 500 in RED_A on router RED-1"
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": NETWORK1_1[addr_type],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "tag": 500,
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {
+ "red1": {
+ "bgp": {
+ "local_as": "500",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {"unicast": {"redistribute": [{"redist_type": "static"}]}},
+ "ipv6": {"unicast": {"redistribute": [{"redist_type": "static"}]}},
+ },
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that static routes(IPv4+IPv6) is overridden and doesn't"
+ " have duplicate entries within VRF RED_A on router RED-1"
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "red1"
+ input_dict_2 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": NETWORK1_1[addr_type],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "tag": 500,
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2, tag=500)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step("Make sure routes are not present in global routing table")
+
+ for addr_type in ADDR_TYPES:
+ dut = "red1"
+ input_dict_2 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": NETWORK1_1[addr_type],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ }
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2, expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n Expected Behaviour: Routes are not "
+ "present on Global Routing table \n Error {}".format(tc_name, result)
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_ambiguous_overlapping_addresses_in_different_vrfs_p0(request):
+ """
+ FUNC_2:
+ Different VRFs can have ambiguous/overlapping
+ addresses on DUT.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step("Configure a set of static routes(IPv4+IPv6) in vrf RED_A" "on router RED-1")
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Configure the same static routes(IPv4+IPv6) with a"
+ " TAG value of 500 in vrf RED_B on router RED-1"
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "tag": 500,
+ "vrf": "RED_B",
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {}
+ for dut in ["red1"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ if "red" in dut:
+ VRFS = ["RED_A", "RED_B"]
+ AS_NUM = [500, 500]
+ elif "blue" in dut:
+ VRFS = ["BLUE_A", "BLUE_B"]
+ AS_NUM = [800, 800]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify that RED_A has the static routes without any" " TAG value")
+
+ for addr_type in ADDR_TYPES:
+ dut = "red1"
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_1, tag=500, expected=False)
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+ logger.info("Expected Behavior: {}".format(result))
+
+ step(
+ "Verify that RED_B has the same routes with TAG value "
+ "500 on same device RED-1"
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "red1"
+ input_dict_2 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "tag": 500,
+ "vrf": "RED_B",
+ }
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2, tag=500)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step("Make sure routes are not present in global routing table")
+
+ for addr_type in ADDR_TYPES:
+ dut = "red1"
+ input_dict_2 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ }
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2, expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n Expected Behaviour: Routes are not "
+ "present on Global Routing table \n Error {}".format(tc_name, result)
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_static_routes_associated_to_specific_vrfs_p0(request):
+ """
+ FUNC_3:
+ Create static routes(IPv4+IPv6) associated to specific VRFs
+ and verify on DUT that same prefixes are present in corresponding
+ routing table.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step(
+ "Configure a set of unique static(IPv4+IPv6) routes in vrf"
+ " RED_A on router RED-1"
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Configure set of unique static routes(IPv4+IPv6) in vrf "
+ "RED_B on router RED-1"
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {}
+ for dut in ["red1", "blue1"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ if "red" in dut:
+ VRFS = ["RED_A", "RED_B"]
+ AS_NUM = [500, 500]
+ elif "blue" in dut:
+ VRFS = ["BLUE_A", "BLUE_B"]
+ AS_NUM = [800, 800]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that static routes 1.x.x.x/32 and 1::x/128 appear" "in VRF RED_A table"
+ )
+ step(
+ "Verify that static routes 2.x.x.x/32 and 2::x/128 appear" "in VRF RED_B table"
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "red1"
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that static routes 1.x.x.x/32 and 1::x/128 appear" "in VRF BLUE_A table"
+ )
+ step(
+ "Verify that static routes 2.x.x.x/32 and 2::x/128 appear" "in VRF BLUE_B table"
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "blue1"
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step("Make sure routes are not present in global routing table")
+
+ for addr_type in ADDR_TYPES:
+ dut = "blue1"
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2, expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n Expected Behaviour: Routes are not "
+ "present on Global Routing table \n Error {}".format(tc_name, result)
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_vrf_with_unique_physical_interface_p0(request):
+ """
+ FUNC_4_&_5:
+ Each VRF should be mapped with a unique VLAN on DUT
+ for traffic segregation, when using a single physical interface.
+
+ Each VRF should be mapped to a unique physical
+ interface(without VLAN tagging) on DUT for traffic segregation.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step(
+ "R1 is receiving routes in 4 VRFs instances "
+ "(RED_A, RED_B, BLUE_A, BLUE_B) from RED_1 and BLUE_1."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Advertise a set of unique BGP prefixes(IPv4+IPv6) from "
+ "routers RED_1 & BLUE_1 in each VRF using static redistribution"
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {}
+ for dut in ["red1", "blue1"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ if "red" in dut:
+ VRFS = ["RED_A", "RED_B"]
+ AS_NUM = [500, 500]
+ elif "blue" in dut:
+ VRFS = ["BLUE_A", "BLUE_B"]
+ AS_NUM = [800, 800]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Each VRF table on R2 should maintain it's associated "
+ "routes and and accordingly install in zebra"
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "r2"
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_prefixes_leaking_p0(request):
+ """
+ FUNC_6:
+ Advertise same set of prefixes from different VRFs
+ and verify on remote router that these prefixes are not
+ leaking to each other
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step("Configure a set of static routes(IPv4+IPv6) in vrf " "RED_A on router RED-1")
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ }
+ ]
+ },
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ }
+ ]
+ },
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Configure a set of static routes(IPv4+IPv6) in vrf " "BLUE_A on router BLUE-1"
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ }
+ ]
+ },
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ }
+ ]
+ },
+ }
+ result = create_static_routes(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Configure the same set of static routes with a "
+ "metric value of 123 in vrf RED_B on router RED-1"
+ )
+ step(
+ "Configure the same set of static routes with a "
+ "metric value of 123 in vrf BLUE_B on router BLUE-1"
+ )
+
+ input_dict_3 = {
+ "red1": {
+ "bgp": [
+ {
+ "local_as": "500",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ },
+ {
+ "local_as": "500",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {
+ "redist_type": "static",
+ "attribute": {"metric": 123},
+ }
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [
+ {
+ "redist_type": "static",
+ "attribute": {"metric": 123},
+ }
+ ]
+ }
+ },
+ },
+ },
+ ]
+ },
+ "blue1": {
+ "bgp": [
+ {
+ "local_as": "800",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ },
+ {
+ "local_as": "800",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {
+ "redist_type": "static",
+ "attribute": {"metric": 123},
+ }
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [
+ {
+ "redist_type": "static",
+ "attribute": {"metric": 123},
+ }
+ ]
+ }
+ },
+ },
+ },
+ ]
+ },
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify on R1 that RED_A doesn't receive and static "
+ "route with metric value 123"
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "r1"
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ }
+ ]
+ },
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ }
+ ]
+ },
+ }
+
+ input_dict_2 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ }
+ ]
+ },
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ }
+ ]
+ },
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_1, metric=123, expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+ logger.info("Expected Behavior: {}".format(result))
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2, metric=123)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_2, metric=0, expected=False
+ )
+ assert result is not True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+ logger.info("Expected Behavior: {}".format(result))
+
+ write_test_footer(tc_name)
+
+
+def test_static_routes_advertised_within_specific_vrf_p0(request):
+ """
+ FUNC_7:
+ Redistribute Static routes and verify on remote routers
+ that routes are advertised within specific VRF instance, which
+ those static routes belong to.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step(
+ "Advertise a set of unique BGP prefixes(IPv4+IPv6) "
+ "through static redistribution into VRF RED_A and RED_B"
+ " from router RED-1."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Advertise same as above set of BGP prefixes(IPv4+IPv6) "
+ "through static redistribution into VRF BLUE_A and BLUE_B"
+ " from router BLUE-1."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {}
+ for dut in ["red1", "blue1"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ if "red" in dut:
+ VRFS = ["RED_A", "RED_B"]
+ AS_NUM = [500, 500]
+ elif "blue" in dut:
+ VRFS = ["BLUE_A", "BLUE_B"]
+ AS_NUM = [800, 800]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that static routes are installed into vrfs RED_A"
+ "and RED_B tables only, not in global routing table of RED_1"
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "red1"
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_1, protocol="static")
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that static routes are installed into vrfs BLUE_A and"
+ "BLUE_B tables only, not in global routing table of BLUE_1."
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "blue1"
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2, protocol="static")
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify on router R1, that each set of prefixes is received"
+ " into associated vrf tables only."
+ )
+
+ result = verify_bgp_convergence(tgen, topo)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+ dut = "r1"
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_end_to_end_traffic_isolation_p0(request):
+ """
+ FUNC_8:
+ Test end to end traffic isolation based on VRF tables.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step(
+ "Advertise unique BGP prefixes(IPv4+IPv6) from RED_1 "
+ "in vrf instances(RED_A and RED_B)."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Advertise unique BGP prefixes(IPv4+IPv6) from from BLUE_1 in"
+ " vrf instances(BLUE_A and BLUE_B)."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {}
+ for dut in ["red1", "blue1"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ if "red" in dut:
+ VRFS = ["RED_A", "RED_B"]
+ AS_NUM = [500, 500]
+ elif "blue" in dut:
+ VRFS = ["BLUE_A", "BLUE_B"]
+ AS_NUM = [800, 800]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Use below commands to send prefixes with as-path prepend"
+ "VRF BLUE_A and BLUE_B from router BLUE-1."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "blue1": {
+ "route_maps": {
+ "ASP_{}".format(addr_type): [
+ {
+ "action": "permit",
+ "set": {"path": {"as_num": 123, "as_action": "prepend"}},
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Apply route-map to neighbours")
+
+ input_dict_5 = {
+ "blue1": {
+ "bgp": [
+ {
+ "local_as": "800",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "blue1-link1": {
+ "route_maps": [
+ {
+ "name": "ASP_ipv4",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "blue1-link1": {
+ "route_maps": [
+ {
+ "name": "ASP_ipv6",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "800",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "blue1-link2": {
+ "route_maps": [
+ {
+ "name": "ASP_ipv4",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "blue1-link2": {
+ "route_maps": [
+ {
+ "name": "ASP_ipv6",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ ]
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_5)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify on R1 that BLUE_A and BLUE_B VRFs are receiving the"
+ " prefixes with as-path 123 prepended."
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "r1"
+ input_dict_6 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ ]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_6)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_6)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "r1"
+ input_dict_7 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ {
+ "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_7)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_7)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Use below commands to send prefixes with as-path prepend VRF"
+ " BLUE_A and BLUE_B from router BLUE-1."
+ )
+
+ input_dict_6 = {
+ "red2": {
+ "bgp": [
+ {
+ "local_as": "500",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "red2-link1": {
+ "allowas-in": {"number_occurences": 2}
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "red2-link1": {
+ "allowas-in": {"number_occurences": 2}
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "500",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "red2-link2": {
+ "allowas-in": {"number_occurences": 2}
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "red2-link2": {
+ "allowas-in": {"number_occurences": 2}
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ ]
+ },
+ "blue2": {
+ "bgp": [
+ {
+ "local_as": "800",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "blue2-link1": {
+ "allowas-in": {"number_occurences": 2}
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "blue2-link1": {
+ "allowas-in": {"number_occurences": 2}
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "800",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "blue2-link2": {
+ "allowas-in": {"number_occurences": 2}
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "blue2-link2": {
+ "allowas-in": {"number_occurences": 2}
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ ]
+ },
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_6)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify that router RED-2 receives the prefixes in respective" " VRF tables.")
+
+ for addr_type in ADDR_TYPES:
+ dut = "red2"
+ input_dict_6 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_6)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_6)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "blue2"
+ input_dict_7 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_7)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_7)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_static_routes_for_inter_vrf_route_leaking_p0(request):
+ """
+ FUNC_9:
+ Use static routes for inter-vrf communication
+ (route-leaking) on DUT.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step(
+ "Configure unique loopback interfaces in VRFs RED_A "
+ "and RED_B on router RED_1."
+ )
+
+ for addr_type in ADDR_TYPES:
+ create_interface_in_kernel(
+ tgen,
+ "red1",
+ "loopback1",
+ LOOPBACK_1[addr_type],
+ "RED_A",
+ LOOPBACK_1["{}_mask".format(addr_type)],
+ )
+ create_interface_in_kernel(
+ tgen,
+ "red1",
+ "loopback2",
+ LOOPBACK_2[addr_type],
+ "RED_B",
+ LOOPBACK_2["{}_mask".format(addr_type)],
+ )
+
+ step(
+ "Create a static routes in vrf RED_B on router RED_1 pointing"
+ " next-hop as interface's IP in vrf RED_A"
+ )
+
+ intf_red1_r11 = topo["routers"]["red1"]["links"]["r1-link1"]["interface"]
+ intf_red1_r10 = topo["routers"]["red1"]["links"]["r1-link2"]["interface"]
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": LOOPBACK_1[addr_type],
+ "interface": intf_red1_r10,
+ "nexthop_vrf": "RED_B",
+ "vrf": "RED_A",
+ },
+ {
+ "network": LOOPBACK_2[addr_type],
+ "interface": intf_red1_r11,
+ "nexthop_vrf": "RED_A",
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {}
+ for dut in ["red1"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ if "red" in dut:
+ VRFS = ["RED_A", "RED_B"]
+ AS_NUM = [500, 500]
+ elif "blue" in dut:
+ VRFS = ["BLUE_A", "BLUE_B"]
+ AS_NUM = [800, 800]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that static routes are installed into vrfs RED_A"
+ "and RED_B tables only, not in global routing table of RED_1"
+ )
+ for addr_type in ADDR_TYPES:
+ dut = "red1"
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": LOOPBACK_1[addr_type],
+ "interface": intf_red1_r10,
+ "nexthop_vrf": "RED_B",
+ "vrf": "RED_A",
+ },
+ {
+ "network": LOOPBACK_2[addr_type],
+ "interface": intf_red1_r11,
+ "nexthop_vrf": "RED_A",
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_1, protocol="static")
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_inter_vrf_and_intra_vrf_communication_iBGP_p0(request):
+ """
+ FUNC_10:
+ Verify intra-vrf and inter-vrf communication between
+ iBGP peers.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step(
+ "Configure unique loopback IP(IPv4+IPv6) in vrf RED_A on router"
+ " R1 and advertise it in BGP process using redistribute "
+ "connected command."
+ )
+
+ for addr_type in ADDR_TYPES:
+ create_interface_in_kernel(
+ tgen,
+ "r1",
+ "loopback1",
+ LOOPBACK_1[addr_type],
+ "RED_A",
+ LOOPBACK_1["{}_mask".format(addr_type)],
+ )
+
+ create_interface_in_kernel(
+ tgen,
+ "r1",
+ "loopback2",
+ LOOPBACK_2[addr_type],
+ "BLUE_A",
+ LOOPBACK_2["{}_mask".format(addr_type)],
+ )
+
+ step(
+ "Create a static routes in vrf RED_B on router RED_1 pointing"
+ " next-hop as interface's IP in vrf RED_A"
+ )
+
+ intf_r2_r12 = topo["routers"]["r2"]["links"]["r1-link1"]["interface"]
+ intf_r2_r10 = topo["routers"]["r2"]["links"]["r1-link3"]["interface"]
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": LOOPBACK_2[addr_type],
+ "interface": intf_r2_r10,
+ "nexthop_vrf": "BLUE_A",
+ "vrf": "RED_A",
+ },
+ {
+ "network": LOOPBACK_1[addr_type],
+ "interface": intf_r2_r12,
+ "nexthop_vrf": "RED_A",
+ "vrf": "BLUE_A",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute connected..")
+
+ input_dict_3 = {}
+ for dut in ["r1"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ VRFS = ["RED_A", "BLUE_A"]
+ AS_NUM = [100, 100]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "connected"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "connected"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Redistribute static..")
+
+ input_dict_3 = {}
+ for dut in ["r2"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ VRFS = ["RED_A", "BLUE_A"]
+ AS_NUM = [100, 100]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that static routes are installed into vrfs RED_A"
+ "and RED_B tables only, not in global routing table of RED_1"
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "r2"
+ input_dict = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": LOOPBACK_2[addr_type],
+ "interface": intf_r2_r10,
+ "nexthop_vrf": "BLUE_A",
+ "vrf": "RED_A",
+ },
+ {
+ "network": LOOPBACK_1[addr_type],
+ "interface": intf_r2_r12,
+ "nexthop_vrf": "RED_A",
+ "vrf": "BLUE_A",
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_inter_vrf_and_intra_vrf_communication_eBGP_p0(request):
+ """
+ FUNC_11:
+ Verify intra-vrf and inter-vrf communication
+ between eBGP peers.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step(
+ "Configure unique loopback IP(IPv4+IPv6) in vrf RED_A on router"
+ " R2 and advertise it in BGP process using redistribute "
+ "connected command."
+ )
+
+ step(
+ "Configure unique loopback IP(IPv4+IPv6) in vrf BLUE_A on router"
+ " R2 and advertise it in BGP process using redistribute "
+ "connected command."
+ )
+
+ for addr_type in ADDR_TYPES:
+ create_interface_in_kernel(
+ tgen,
+ "r2",
+ "loopback1",
+ LOOPBACK_1[addr_type],
+ "RED_A",
+ LOOPBACK_1["{}_mask".format(addr_type)],
+ )
+ create_interface_in_kernel(
+ tgen,
+ "r2",
+ "loopback2",
+ LOOPBACK_2[addr_type],
+ "BLUE_A",
+ LOOPBACK_2["{}_mask".format(addr_type)],
+ )
+
+ step(
+ "Create a static routes in vrf RED_B on router RED_1 pointing"
+ " next-hop as interface's IP in vrf RED_A"
+ )
+
+ intf_r3_r21 = topo["routers"]["r3"]["links"]["r2-link1"]["interface"]
+ intf_r3_r23 = topo["routers"]["r3"]["links"]["r2-link3"]["interface"]
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "r3": {
+ "static_routes": [
+ {
+ "network": LOOPBACK_2[addr_type],
+ "interface": intf_r3_r23,
+ "nexthop_vrf": "BLUE_A",
+ "vrf": "RED_A",
+ },
+ {
+ "network": LOOPBACK_1[addr_type],
+ "interface": intf_r3_r21,
+ "nexthop_vrf": "RED_A",
+ "vrf": "BLUE_A",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {}
+ for dut in ["r3"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ VRFS = ["RED_A", "BLUE_A"]
+ AS_NUM = [200, 200]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Redistribute connected..")
+
+ input_dict_3 = {}
+ for dut in ["r2"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ VRFS = ["RED_A", "BLUE_A"]
+ AS_NUM = [100, 100]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "connected"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "connected"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that static routes are installed into vrfs RED_A"
+ "and RED_B tables only, not in global routing table of RED_1"
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "r3"
+ input_dict = {
+ "r3": {
+ "static_routes": [
+ {
+ "network": LOOPBACK_2[addr_type],
+ "interface": intf_r3_r23,
+ "nexthop_vrf": "BLUE_A",
+ "vrf": "RED_A",
+ },
+ {
+ "network": LOOPBACK_1[addr_type],
+ "interface": intf_r3_r21,
+ "nexthop_vrf": "RED_A",
+ "vrf": "BLUE_A",
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_route_map_within_vrf_to_alter_bgp_attribute_nexthop_p0(request):
+ """
+ FUNC_12_a:
+ Configure route-maps within a VRF, to alter BGP attributes.
+ Verify that route-map doesn't affect any other VRF instances'
+ routing on DUT.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step(
+ "Advertise a set of BGP prefixes(IPv4+IPv6) from RED_1 and"
+ " RED_2 in vrf instances(RED_A and RED_B)."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Advertise same set of BGP prefixes(IPv4+IPv6) from BLUE_1 and"
+ "BLUE_2 in vrf instances(BLUE_A and BLUE_B)"
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {}
+ for dut in ["red1", "blue1"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ if "red" in dut:
+ VRFS = ["RED_A", "RED_B"]
+ AS_NUM = [500, 500]
+ elif "blue" in dut:
+ VRFS = ["BLUE_A", "BLUE_B"]
+ AS_NUM = [800, 800]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that within vrf instances, BGP best path selection"
+ " algorithm remains intact and doesn't affect any other VRFs"
+ " routing decision."
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "r2"
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step("Delete nexthop-self configure from r1")
+
+ input_dict_4 = {
+ "r1": {
+ "bgp": [
+ {
+ "local_as": "100",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"next_hop_self": False}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {"next_hop_self": False}
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link2": {"next_hop_self": False}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link2": {"next_hop_self": False}
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link3": {"next_hop_self": False}
+ }
+ },
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link3": {"next_hop_self": False}
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link4": {"next_hop_self": False}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link4": {"next_hop_self": False}
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ ]
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that within vrf instances, BGP best path selection"
+ " algorithm remains intact and doesn't affect any other VRFs"
+ " routing decision."
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "r2"
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False)
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n Expected Behaviour: Routes are rejected because"
+ " nexthop-self config is deleted \n Error {}".format(tc_name, result)
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2, expected=False)
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n Expected Behaviour: Routes are rejected because"
+ " nexthop-self config is deleted \n Error {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+@pytest.mark.parametrize("attribute", ["locPrf", "weight", "metric"])
+def test_route_map_within_vrf_to_alter_bgp_attribute_p0(request, attribute):
+ """
+ FUNC_12_b/c/d:
+ Configure route-maps within a VRF, to alter BGP attributes.
+ Verify that route-map doesn't affect any other VRF instances'
+ routing on DUT.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step(
+ "Advertise a set of BGP prefixes(IPv4+IPv6) from RED_1 and"
+ " RED_2 in vrf instances(RED_A and RED_B)."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ },
+ "red2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ },
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Advertise same set of BGP prefixes(IPv4+IPv6) from BLUE_1 and"
+ "BLUE_2 in vrf instances(BLUE_A and BLUE_B)"
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ },
+ "blue2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ },
+ }
+ result = create_static_routes(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {}
+ for dut in ["red1", "red2", "blue1", "blue2"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ if "red" in dut:
+ VRFS = ["RED_A", "RED_B"]
+ AS_NUM = [500, 500]
+ elif "blue" in dut:
+ VRFS = ["BLUE_A", "BLUE_B"]
+ AS_NUM = [800, 800]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Configure a route-maps to influence BGP parameters - " " Local Preference")
+
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "r2": {
+ "route_maps": {
+ "rmap_r1_{}".format(addr_type): [
+ {"action": "permit", "set": {attribute: 120}}
+ ],
+ "rmap_r3_{}".format(addr_type): [
+ {"action": "permit", "set": {attribute: 150}}
+ ],
+ }
+ }
+ }
+
+ result = create_route_maps(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure neighbor for route map")
+ input_dict_4 = {
+ "r2": {
+ "bgp": [
+ {
+ "local_as": "100",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link1": {
+ "route_maps": [
+ {
+ "name": "rmap_r3_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link1": {
+ "route_maps": [
+ {
+ "name": "rmap_r3_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link2": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link2": {
+ "route_maps": [
+ {
+ "name": "rmap_r3_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link2": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link2": {
+ "route_maps": [
+ {
+ "name": "rmap_r3_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link3": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link3": {
+ "route_maps": [
+ {
+ "name": "rmap_r3_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link3": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link3": {
+ "route_maps": [
+ {
+ "name": "rmap_r3_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link4": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link4": {
+ "route_maps": [
+ {
+ "name": "rmap_r3_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link4": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link4": {
+ "route_maps": [
+ {
+ "name": "rmap_r3_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ }
+ }
+ },
+ },
+ },
+ ]
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that within vrf instances, BGP best path selection"
+ " algorithm remains intact and doesn't affect any other VRFs"
+ " routing decision."
+ )
+
+ dut = "r2"
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+
+ result = verify_best_path_as_per_bgp_attribute(
+ tgen, addr_type, dut, input_dict_1, attribute
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_best_path_as_per_bgp_attribute(
+ tgen, addr_type, dut, input_dict_2, attribute
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_route_map_within_vrf_to_alter_bgp_attribute_aspath_p0(request):
+ """
+ FUNC_12_e:
+ Configure route-maps within a VRF, to alter BGP attributes.
+ Verify that route-map doesn't affect any other VRF instances'
+ routing on DUT.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step(
+ "Advertise a set of BGP prefixes(IPv4+IPv6) from RED_1 and"
+ " RED_2 in vrf instances(RED_A and RED_B)."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ },
+ "red2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ },
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Advertise same set of BGP prefixes(IPv4+IPv6) from BLUE_1 and"
+ "BLUE_2 in vrf instances(BLUE_A and BLUE_B)"
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ },
+ "blue2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ },
+ }
+ result = create_static_routes(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {}
+ for dut in ["red1", "red2", "blue1", "blue2"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ if "red" in dut:
+ VRFS = ["RED_A", "RED_B"]
+ AS_NUM = [500, 500]
+ elif "blue" in dut:
+ VRFS = ["BLUE_A", "BLUE_B"]
+ AS_NUM = [800, 800]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Configure a route-maps to influence BGP parameters - " " Local Preference")
+
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "r2": {
+ "route_maps": {
+ "rmap_r1_{}".format(addr_type): [
+ {
+ "action": "permit",
+ "set": {
+ "path": {"as_num": "111 222", "as_action": "prepend"}
+ },
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure neighbor for route map")
+ input_dict_4 = {
+ "r2": {
+ "bgp": [
+ {
+ "local_as": "100",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ "r3": {"dest_link": {"r2-link1": {}}},
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ "r3": {"dest_link": {"r2-link1": {}}},
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link2": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ "r3": {"dest_link": {"r2-link2": {}}},
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link2": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ "r3": {"dest_link": {"r2-link2": {}}},
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link3": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ "r3": {"dest_link": {"r2-link3": {}}},
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link3": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ "r3": {"dest_link": {"r2-link3": {}}},
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link4": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ "r3": {"dest_link": {"r2-link4": {}}},
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link4": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ "r3": {"dest_link": {"r2-link4": {}}},
+ }
+ }
+ },
+ },
+ },
+ ]
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that within vrf instances, BGP best path selection"
+ " algorithm remains intact and doesn't affect any other VRFs"
+ " routing decision."
+ )
+
+ dut = "r2"
+ attribute = "path"
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+
+ result = verify_best_path_as_per_bgp_attribute(
+ tgen, addr_type, dut, input_dict_1, attribute
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_best_path_as_per_bgp_attribute(
+ tgen, addr_type, dut, input_dict_2, attribute
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_route_map_within_vrf_to_alter_bgp_attribute_lcomm_p0(request):
+ """
+ FUNC_12_f:
+ Configure route-maps within a VRF, to alter BGP attributes.
+ Verify that route-map doesn't affect any other VRF instances'
+ routing on DUT.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step(
+ "Advertise a set of BGP prefixes(IPv4+IPv6) from RED_1 and"
+ " RED_2 in vrf instances(RED_A and RED_B)."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ },
+ "red2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ },
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Advertise same set of BGP prefixes(IPv4+IPv6) from BLUE_1 and"
+ "BLUE_2 in vrf instances(BLUE_A and BLUE_B)"
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ },
+ "blue2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ },
+ }
+ result = create_static_routes(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {}
+ for dut in ["red1", "red2", "blue1", "blue2"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ if "red" in dut:
+ VRFS = ["RED_A", "RED_B"]
+ AS_NUM = [500, 500]
+ elif "blue" in dut:
+ VRFS = ["BLUE_A", "BLUE_B"]
+ AS_NUM = [800, 800]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Configure a route-maps to influence BGP parameters - " " Large-community")
+
+ step("Create standard large commumity-list in r2")
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "r2": {
+ "bgp_community_lists": [
+ {
+ "community_type": "standard",
+ "action": "permit",
+ "name": "rmap_lcomm_{}".format(addr_type),
+ "value": "1:1:1 1:2:3 2:1:1 2:2:2",
+ "large": True,
+ }
+ ]
+ }
+ }
+ result = create_bgp_community_lists(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Create route-maps in red1 and r1")
+
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "red1": {
+ "route_maps": {
+ "rmap_red1_{}".format(addr_type): [
+ {
+ "action": "permit",
+ "set": {
+ "large_community": {"num": "1:1:1 1:2:3 2:1:1 2:2:2"}
+ },
+ }
+ ]
+ }
+ },
+ "r2": {
+ "route_maps": {
+ "rmap_r1_{}".format(addr_type): [
+ {
+ "action": "permit",
+ "match": {
+ "large_community_list": {
+ "id": "rmap_lcomm_" + addr_type
+ }
+ },
+ }
+ ]
+ }
+ },
+ }
+ result = create_route_maps(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure neighbor for route map in red1")
+
+ input_dict_4 = {
+ "red1": {
+ "bgp": [
+ {
+ "local_as": "500",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link1": {
+ "route_maps": [
+ {
+ "name": "rmap_red1_ipv4",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link1": {
+ "route_maps": [
+ {
+ "name": "rmap_red1_ipv6",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "500",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link2": {
+ "route_maps": [
+ {
+ "name": "rmap_red1_ipv4",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link2": {
+ "route_maps": [
+ {
+ "name": "rmap_red1_ipv6",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ ]
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Configure neighbor for route map in r2")
+
+ input_dict_4 = {
+ "r2": {
+ "bgp": [
+ {
+ "local_as": "100",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link2": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link2": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link3": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link3": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link4": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link4": {
+ "route_maps": [
+ {
+ "name": "rmap_r1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ ]
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "All the prefixes advertised from RED_1 and BLUE_1 should carry"
+ " attributes set by outbound route-maps within specific vrfs. "
+ "Router R1 should be able to match and permit/deny those "
+ "prefixes based on received attributes. Please use below "
+ "commands to verify."
+ )
+
+ input_dict = {
+ "largeCommunity": "1:1:1 1:2:3 2:1:1 2:2:2",
+ }
+
+ for addr_type in ADDR_TYPES:
+ vrf = "RED_A"
+ routes = [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]]
+ result = verify_bgp_community(tgen, addr_type, "r2", routes, input_dict, vrf)
+ assert result is True, "Test case {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ vrf = "RED_B"
+ routes = [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]]
+ result = verify_bgp_community(tgen, addr_type, "r2", routes, input_dict, vrf)
+ assert result is True, "Test case {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_route_map_match_traffic_based_on_vrf_p0(request):
+ """
+ FUNC_13:
+ Configure a route-map on DUT to match traffic based
+ on a VRF interfaces.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step(
+ "Advertise unique BGP prefixes(IPv4+IPv6) from RED_1 "
+ "in vrf instances(RED_A and RED_B)."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Advertise unique BGP prefixes(IPv4+IPv6) from from BLUE_1 in"
+ " vrf instances(BLUE_A and BLUE_B)."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {}
+ for dut in ["red1", "blue1"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ if "red" in dut:
+ VRFS = ["RED_A", "RED_B"]
+ AS_NUM = [500, 500]
+ elif "blue" in dut:
+ VRFS = ["BLUE_A", "BLUE_B"]
+ AS_NUM = [800, 800]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Configure a route-map on R1 to match the prefixes "
+ "coming from vrf RED_A and set as-prepend to these routes."
+ )
+
+ input_dict_4 = {
+ "r1": {
+ "route_maps": {
+ "ABC": [
+ {
+ "action": "permit",
+ "match": {"source-vrf": "RED_A"},
+ "set": {"path": {"as_num": 1, "as_action": "prepend"}},
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "On R1, import the routes form vrf RED_A and RED_B to BLUE_A and"
+ " apply the route-map under vrf BLUE_A while importing"
+ )
+
+ raw_config = {
+ "r1": {
+ "raw_config": [
+ "router bgp 100 vrf BLUE_A",
+ "address-family ipv4 unicast",
+ "import vrf RED_A",
+ "import vrf RED_B",
+ "import vrf route-map ABC",
+ "address-family ipv6 unicast",
+ "import vrf RED_A",
+ "import vrf RED_B",
+ "import vrf route-map ABC",
+ ]
+ }
+ }
+ result = apply_raw_config(tgen, raw_config)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step(
+ "All the prefixes advertised from RED_1 and BLUE_1 in vrfs "
+ "RED_B and BLUE_B must prepend the AS number in as-path on R2."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_7 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ ]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_dict_7)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_vrf_lite_with_static_bgp_originated_routes_p0(request):
+ """
+ FUNC_14:
+ Test VRF-lite with Static+BGP originated routes.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step(
+ "Advertise unique BGP prefixes(IPv4+IPv6) from from RED_1"
+ " in vrf instances(RED_A and RED_B)."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Advertise unique BGP prefixes(IPv4+IPv6) from from BLUE_1 in"
+ " vrf instances(BLUE_A and BLUE_B)."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ input_dict_3 = {
+ "red1": {
+ "bgp": [
+ {
+ "local_as": "500",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": [NETWORK5_1["ipv4"]]
+ + [NETWORK5_2["ipv4"]]
+ }
+ ],
+ "redistribute": [{"redist_type": "static"}],
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": [NETWORK5_1["ipv6"]]
+ + [NETWORK5_2["ipv6"]]
+ }
+ ],
+ "redistribute": [{"redist_type": "static"}],
+ }
+ },
+ },
+ },
+ {
+ "local_as": "500",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": [NETWORK6_1["ipv4"]]
+ + [NETWORK6_2["ipv4"]]
+ }
+ ],
+ "redistribute": [{"redist_type": "static"}],
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": [NETWORK6_1["ipv6"]]
+ + [NETWORK6_2["ipv6"]]
+ }
+ ],
+ "redistribute": [{"redist_type": "static"}],
+ }
+ },
+ },
+ },
+ ]
+ },
+ "blue1": {
+ "bgp": [
+ {
+ "local_as": "800",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": [NETWORK7_1["ipv4"]]
+ + [NETWORK7_2["ipv4"]]
+ }
+ ],
+ "redistribute": [{"redist_type": "static"}],
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": [NETWORK7_1["ipv6"]]
+ + [NETWORK7_2["ipv6"]]
+ }
+ ],
+ "redistribute": [{"redist_type": "static"}],
+ }
+ },
+ },
+ },
+ {
+ "local_as": "800",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": [NETWORK8_1["ipv4"]]
+ + [NETWORK8_2["ipv4"]]
+ }
+ ],
+ "redistribute": [{"redist_type": "static"}],
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": [NETWORK8_1["ipv6"]]
+ + [NETWORK8_2["ipv6"]]
+ }
+ ],
+ "redistribute": [{"redist_type": "static"}],
+ }
+ },
+ },
+ },
+ ]
+ },
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Static routes must be installed in associated VRF" " table only.")
+
+ for addr_type in ADDR_TYPES:
+ dut = "r1"
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step(
+ "All the routers must receive advertised as well as "
+ "redistributed(static) prefixes in associated VRF tables."
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "r1"
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_prefix_list_to_permit_deny_prefixes_p0(request):
+ """
+ FUNC_15:
+ Configure prefix-lists on DUT and apply to BGP peers to
+ permit/deny prefixes.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step(
+ "Advertise unique BGP prefixes(IPv4+IPv6) from from RED_1"
+ " in vrf instances(RED_A and RED_B)."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Advertise unique BGP prefixes(IPv4+IPv6) from from BLUE_1 in"
+ " vrf instances(BLUE_A and BLUE_B)."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {}
+ for dut in ["red1", "blue1"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ if "red" in dut:
+ VRFS = ["RED_A", "RED_B"]
+ AS_NUM = [500, 500]
+ elif "blue" in dut:
+ VRFS = ["BLUE_A", "BLUE_B"]
+ AS_NUM = [800, 800]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify routes are present before applying prefix-list")
+ for addr_type in ADDR_TYPES:
+ dut = "r1"
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step(
+ "On routers RED_1 and BLUE_1, configure prefix-lists to permit"
+ " 4 prefixes and deny 1 prefix x.x.x.5. Apply these in outbound"
+ "direction for each neighbour."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "red1": {
+ "prefix_lists": {
+ addr_type: {
+ "pflist_red1_{}".format(addr_type): [
+ {
+ "seqid": 10,
+ "network": NETWORK1_1[addr_type],
+ "action": "permit",
+ },
+ {
+ "seqid": 11,
+ "network": NETWORK2_1[addr_type],
+ "action": "permit",
+ },
+ {
+ "seqid": 12,
+ "network": NETWORK1_2[addr_type],
+ "action": "deny",
+ },
+ {
+ "seqid": 13,
+ "network": NETWORK2_2[addr_type],
+ "action": "deny",
+ },
+ ]
+ }
+ }
+ },
+ "blue1": {
+ "prefix_lists": {
+ addr_type: {
+ "pflist_blue1_{}".format(addr_type): [
+ {
+ "seqid": 10,
+ "network": NETWORK1_1[addr_type],
+ "action": "permit",
+ },
+ {
+ "seqid": 11,
+ "network": NETWORK2_1[addr_type],
+ "action": "permit",
+ },
+ {
+ "seqid": 12,
+ "network": NETWORK1_2[addr_type],
+ "action": "deny",
+ },
+ {
+ "seqid": 13,
+ "network": NETWORK2_2[addr_type],
+ "action": "deny",
+ },
+ ]
+ }
+ }
+ },
+ "r1": {
+ "prefix_lists": {
+ addr_type: {
+ "pflist_r1_{}".format(addr_type): [
+ {
+ "seqid": 10,
+ "network": NETWORK1_1[addr_type],
+ "action": "permit",
+ },
+ {
+ "seqid": 11,
+ "network": NETWORK2_1[addr_type],
+ "action": "deny",
+ },
+ ]
+ }
+ }
+ },
+ }
+ result = create_prefix_lists(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ input_dict_5 = {
+ "red1": {
+ "bgp": [
+ {
+ "local_as": "500",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link1": {
+ "prefix_lists": [
+ {
+ "name": "pflist_red1_ipv4",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link1": {
+ "prefix_lists": [
+ {
+ "name": "pflist_red1_ipv6",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "500",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link2": {
+ "prefix_lists": [
+ {
+ "name": "pflist_red1_ipv4",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link2": {
+ "prefix_lists": [
+ {
+ "name": "pflist_red1_ipv6",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ ]
+ },
+ "blue1": {
+ "bgp": [
+ {
+ "local_as": "800",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "blue1-link1": {
+ "prefix_lists": [
+ {
+ "name": "pflist_blue1_ipv4",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "blue1-link1": {
+ "prefix_lists": [
+ {
+ "name": "pflist_blue1_ipv6",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "800",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "blue1-link2": {
+ "prefix_lists": [
+ {
+ "name": "pflist_blue1_ipv4",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "blue1-link2": {
+ "prefix_lists": [
+ {
+ "name": "pflist_blue1_ipv6",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ ]
+ },
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_5)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that within vrf instances, each BGP neighbor receives 1"
+ " prefixes in routing table and drops (x.x.x.2)."
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "r1"
+ permitted_routes = {
+ "red1": {
+ "static_routes": [
+ {"network": [NETWORK1_1[addr_type]], "vrf": "RED_A"},
+ {"network": [NETWORK2_1[addr_type]], "vrf": "RED_B"},
+ ]
+ }
+ }
+
+ denied_routes = {
+ "red1": {
+ "static_routes": [
+ {"network": [NETWORK1_2[addr_type]], "vrf": "RED_A"},
+ {"network": [NETWORK2_2[addr_type]], "vrf": "RED_B"},
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, permitted_routes)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(tgen, addr_type, dut, denied_routes, expected=False)
+ assert result is not True, "Testcase {} : Failed \n"
+ "Expected behaviour: Routes are denied by prefix-list \n"
+ "Error {}".format(tc_name, result)
+
+ step(
+ "On router R1, configure prefix-lists to permit 2 "
+ "prefixes(x.x.x.1-2) and deny 2 prefix(x.x.x.3-4). Apply"
+ " these in inbound direction for each neighbour."
+ )
+
+ input_dict_6 = {
+ "r1": {
+ "bgp": [
+ {
+ "local_as": "100",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link1": {
+ "prefix_lists": [
+ {
+ "name": "pflist_r1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link1": {
+ "prefix_lists": [
+ {
+ "name": "pflist_r1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link2": {
+ "prefix_lists": [
+ {
+ "name": "pflist_r1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link2": {
+ "prefix_lists": [
+ {
+ "name": "pflist_r1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link1": {
+ "prefix_lists": [
+ {
+ "name": "pflist_r1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link1": {
+ "prefix_lists": [
+ {
+ "name": "pflist_r1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link2": {
+ "prefix_lists": [
+ {
+ "name": "pflist_r1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link2": {
+ "prefix_lists": [
+ {
+ "name": "pflist_r1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ ]
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_6)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that within vrf instances, each BGP neighbor installs"
+ " only 1 prefix (x.x.x.1)."
+ )
+ for addr_type in ADDR_TYPES:
+ dut = "r2"
+ permitted_routes = {
+ "red1": {
+ "static_routes": [{"network": [NETWORK1_1[addr_type]], "vrf": "RED_A"}]
+ }
+ }
+
+ denied_routes = {
+ "red1": {
+ "static_routes": [{"network": [NETWORK2_1[addr_type]], "vrf": "RED_A"}]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, permitted_routes)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(tgen, addr_type, dut, denied_routes, expected=False)
+ assert result is not True, "Testcase {} : Failed \n"
+ "Expected behaviour: Routes are denied by prefix-list \n"
+ "Error {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_route_map_set_and_match_tag_p0(request):
+ """
+ FUNC_16_1:
+ Configure a route-map on DUT to match traffic based various
+ match/set causes.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step(
+ "Advertise unique BGP prefixes(IPv4+IPv6) from RED_1"
+ " in vrf instances(RED_A and RED_B)."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "tag": 4001,
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Advertise same set of BGP prefixes(IPv4+IPv6) from BLUE_1 and"
+ "BLUE_2 in vrf instances(BLUE_A and BLUE_B)"
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK3_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "tag": 4001,
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK3_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {}
+ for dut in ["red1", "blue1"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ if "red" in dut:
+ VRFS = ["RED_A", "RED_B"]
+ AS_NUM = [500, 500]
+ elif "blue" in dut:
+ VRFS = ["BLUE_A", "BLUE_B"]
+ AS_NUM = [800, 800]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Configure a route-maps to match tag")
+
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "red1": {
+ "route_maps": {
+ "rmap1_{}".format(addr_type): [
+ {"action": "permit", "match": {addr_type: {"tag": "4001"}}}
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure neighbor for route map")
+ input_dict_4 = {
+ "red1": {
+ "bgp": [
+ {
+ "local_as": "500",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link1": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv4",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link1": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv6",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "500",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link2": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv4",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link2": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv6",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ ]
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that within vrf instances, BGP best path selection"
+ " algorithm remains intact and doesn't affect any other VRFs"
+ " routing decision."
+ )
+
+ dut = "r1"
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "tag": 4001,
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2, expected=False)
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n Expected Behavior: Routes are denied \n"
+ "Error {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_route_map_set_and_match_metric_p0(request):
+ """
+ FUNC_16_2:
+ Configure a route-map on DUT to match traffic based various
+ match/set causes.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step(
+ "Advertise unique BGP prefixes(IPv4+IPv6) from RED_1"
+ " in vrf instances(RED_A and RED_B)."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Advertise same set of BGP prefixes(IPv4+IPv6) from BLUE_1 and"
+ "BLUE_2 in vrf instances(BLUE_A and BLUE_B)"
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {
+ "red1": {
+ "bgp": [
+ {
+ "local_as": "500",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {
+ "redist_type": "static",
+ "attribute": {"metric": 123},
+ }
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [
+ {
+ "redist_type": "static",
+ "attribute": {"metric": 123},
+ }
+ ]
+ }
+ },
+ },
+ },
+ {
+ "local_as": "500",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ },
+ ]
+ },
+ "blue1": {
+ "bgp": [
+ {
+ "local_as": "800",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {
+ "redist_type": "static",
+ "attribute": {"metric": 123},
+ }
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [
+ {
+ "redist_type": "static",
+ "attribute": {"metric": 123},
+ }
+ ]
+ }
+ },
+ },
+ },
+ {
+ "local_as": "800",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ },
+ ]
+ },
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Configure a route-maps to match tag")
+
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "r1": {
+ "route_maps": {
+ "rmap1_{}".format(addr_type): [
+ {"action": "permit", "match": {"metric": 123}}
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure neighbor for route map")
+ input_dict_4 = {
+ "r1": {
+ "bgp": [
+ {
+ "local_as": "100",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link1": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link1": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link2": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link2": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link1": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link1": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link2": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link2": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ ]
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that within vrf instances, BGP best path selection"
+ " algorithm remains intact and doesn't affect any other VRFs"
+ " routing decision."
+ )
+
+ dut = "r1"
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ }
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2, expected=False)
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n Expected Behavior: Routes are denied \n"
+ "Error {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_route_map_set_and_match_community_p0(request):
+ """
+ FUNC_16_3:
+ Configure a route-map on DUT to match traffic based various
+ match/set causes.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step(
+ "Advertise unique BGP prefixes(IPv4+IPv6) from RED_1"
+ " in vrf instances(RED_A and RED_B)."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Advertise same set of BGP prefixes(IPv4+IPv6) from BLUE_1 and"
+ "BLUE_2 in vrf instances(BLUE_A and BLUE_B)"
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {}
+ for dut in ["red1", "blue1"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ if "red" in dut:
+ VRFS = ["RED_A", "RED_B"]
+ AS_NUM = [500, 500]
+ elif "blue" in dut:
+ VRFS = ["BLUE_A", "BLUE_B"]
+ AS_NUM = [800, 800]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Create community-list")
+
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "r1": {
+ "bgp_community_lists": [
+ {
+ "community_type": "standard",
+ "action": "permit",
+ "name": "rmap_lcomm_{}".format(addr_type),
+ "value": "1:1 1:2 1:3 1:4 1:5",
+ }
+ ]
+ }
+ }
+ result = create_bgp_community_lists(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure a route-maps to match tag")
+
+ step("Create route-maps in red1 and r1")
+
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "red1": {
+ "route_maps": {
+ "rmap_red1_{}".format(addr_type): [
+ {
+ "action": "permit",
+ "set": {"community": {"num": "1:1 1:2 1:3 1:4 1:5"}},
+ }
+ ]
+ }
+ },
+ "r1": {
+ "route_maps": {
+ "rmap1_{}".format(addr_type): [
+ {
+ "action": "permit",
+ "match": {
+ "community_list": {"id": "rmap_lcomm_" + addr_type}
+ },
+ }
+ ]
+ }
+ },
+ }
+ result = create_route_maps(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure neighbor for route map")
+ input_dict_4 = {
+ "red1": {
+ "bgp": [
+ {
+ "local_as": "500",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link1": {
+ "route_maps": [
+ {
+ "name": "rmap_red1_ipv4",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link1": {
+ "route_maps": [
+ {
+ "name": "rmap_red1_ipv6",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "500",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link2": {
+ "route_maps": [
+ {
+ "name": "rmap_red1_ipv4",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link2": {
+ "route_maps": [
+ {
+ "name": "rmap_red1_ipv6",
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ ]
+ },
+ "r1": {
+ "bgp": [
+ {
+ "local_as": "100",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link1": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link1": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link2": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link2": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link1": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link1": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link2": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv4",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link2": {
+ "route_maps": [
+ {
+ "name": "rmap1_ipv6",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ ]
+ },
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "All the prefixes advertised from RED_1 and BLUE_1 should carry"
+ " attributes set by outbound route-maps within specific vrfs. "
+ "Router R1 should be able to match and permit/deny those "
+ "prefixes based on received attributes. Please use below "
+ "commands to verify."
+ )
+
+ input_dict = {
+ "community": "1:1 1:2 1:3 1:4 1:5",
+ }
+
+ for addr_type in ADDR_TYPES:
+ vrf = "RED_A"
+ routes = [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]]
+ result = verify_bgp_community(tgen, addr_type, "r1", routes, input_dict, vrf)
+ assert result is True, "Test case {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ vrf = "RED_B"
+ routes = [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]]
+ result = verify_bgp_community(tgen, addr_type, "r1", routes, input_dict, vrf)
+ assert result is True, "Test case {} : 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_multi_vrf_topo2/bgp_multi_vrf_topo2.json b/tests/topotests/bgp_multi_vrf_topo2/bgp_multi_vrf_topo2.json
new file mode 100644
index 0000000000..ab570fcc16
--- /dev/null
+++ b/tests/topotests/bgp_multi_vrf_topo2/bgp_multi_vrf_topo2.json
@@ -0,0 +1,1277 @@
+{
+ "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": {
+ "red1": {
+ "links": {
+ "r1-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "r1-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"}
+ },
+ "vrfs":[
+ {
+ "name": "RED_A",
+ "id": "1"
+ },
+ {
+ "name": "RED_B",
+ "id": "2"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "500",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "500",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "red1-link2": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "blue1": {
+ "links": {
+ "r1-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_A"},
+ "r1-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"}
+ },
+ "vrfs":[
+ {
+ "name": "BLUE_A",
+ "id": "1"
+ },
+ {
+ "name": "BLUE_B",
+ "id": "2"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "800",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "blue1-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "blue1-link1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "800",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "blue1-link2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "blue1-link2": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "r1": {
+ "links": {
+ "red1-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "red1-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"},
+ "blue1-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_A"},
+ "blue1-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"},
+ "r2-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "r2-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"},
+ "r2-link3": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_A"},
+ "r2-link4": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"},
+ "r4-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "r4-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"},
+ "r4-link3": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_A"},
+ "r4-link4": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"}
+ },
+ "vrfs":[
+ {
+ "name": "RED_A",
+ "id": "1"
+ },
+ {
+ "name": "RED_B",
+ "id": "2"
+ },
+ {
+ "name": "BLUE_A",
+ "id": "3"
+ },
+ {
+ "name": "BLUE_B",
+ "id": "4"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "100",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link1": {}
+ }
+ },
+ "r2": {
+ "dest_link": {
+ "r1-link1":
+ { "next_hop_self": true }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r1-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link1": {}
+ }
+ },
+ "r2": {
+ "dest_link": {
+ "r1-link1":
+ { "next_hop_self": true }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r1-link1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link2": {}
+ }
+ },
+ "r2": {
+ "dest_link": {
+ "r1-link2":
+ { "next_hop_self": true }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r1-link2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "red1": {
+ "dest_link": {
+ "r1-link2": {}
+ }
+ },
+ "r2": {
+ "dest_link": {
+ "r1-link2":
+ { "next_hop_self": true }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r1-link2": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link1": {}
+ }
+ },
+ "r2": {
+ "dest_link": {
+ "r1-link3":
+ { "next_hop_self": true }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r1-link3": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link1": {}
+ }
+ },
+ "r2": {
+ "dest_link": {
+ "r1-link3":
+ { "next_hop_self": true }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r1-link3": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link2": {}
+ }
+ },
+ "r2": {
+ "dest_link": {
+ "r1-link4":
+ { "next_hop_self": true }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r1-link4": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "blue1": {
+ "dest_link": {
+ "r1-link2": {}
+ }
+ },
+ "r2": {
+ "dest_link": {
+ "r1-link4":
+ { "next_hop_self": true }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r1-link4": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "r2": {
+ "links": {
+ "r1-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "r1-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"},
+ "r1-link3": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_A"},
+ "r1-link4": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"},
+ "r3-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "r3-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"},
+ "r3-link3": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_A"},
+ "r3-link4": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"}
+ },
+ "vrfs":[
+ {
+ "name": "RED_A",
+ "id": "1"
+ },
+ {
+ "name": "RED_B",
+ "id": "2"
+ },
+ {
+ "name": "BLUE_A",
+ "id": "3"
+ },
+ {
+ "name": "BLUE_B",
+ "id": "4"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "100",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link2": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link2": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link2": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link3": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link3": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link3": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link3": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link4": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link4": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link4": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r2-link4": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "r3": {
+ "links": {
+ "r2-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "r2-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"},
+ "r2-link3": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_A"},
+ "r2-link4": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"},
+ "r4-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "r4-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"},
+ "r4-link3": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_A"},
+ "r4-link4": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"},
+ "red2-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "red2-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"},
+ "blue2-link1": {"ipv4": "auto", "ipv6": "autor3", "vrf": "BLUE_A"},
+ "blue2-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"}
+ },
+ "vrfs":[
+ {
+ "name": "RED_A",
+ "id": "1"
+ },
+ {
+ "name": "RED_B",
+ "id": "2"
+ },
+ {
+ "name": "BLUE_A",
+ "id": "3"
+ },
+ {
+ "name": "BLUE_B",
+ "id": "4"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "200",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {}
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3-link1": {}
+ }
+ },
+ "red2": {
+ "dest_link": {
+ "r3-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3-link1": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ },
+ "red2": {
+ "dest_link": {
+ "r3-link1": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "200",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link2": {}
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3-link2": {}
+ }
+ },
+ "red2": {
+ "dest_link": {
+ "r3-link2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link2": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3-link2": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ },
+ "red2": {
+ "dest_link": {
+ "r3-link2": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "200",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link3": {}
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3-link3": {}
+ }
+ },
+ "blue2": {
+ "dest_link": {
+ "r3-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link3": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3-link3": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ },
+ "blue2": {
+ "dest_link": {
+ "r3-link1": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "200",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link4": {}
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3-link4": {}
+ }
+ },
+ "blue2": {
+ "dest_link": {
+ "r3-link2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link4": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3-link4": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ },
+ "blue2": {
+ "dest_link": {
+ "r3-link2": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ],
+ "route_maps": {
+ "rmap_global": [{
+ "action": "permit",
+ "set": {
+ "ipv6": {
+ "nexthop": "prefer-global"
+ }
+ }
+ }]
+ }
+ },
+ "r4": {
+ "links": {
+ "r1-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "r1-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"},
+ "r1-link3": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_A"},
+ "r1-link4": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"},
+ "r3-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "r3-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"},
+ "r3-link3": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_A"},
+ "r3-link4": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"}
+ },
+ "vrfs":[
+ {
+ "name": "RED_A",
+ "id": "1"
+ },
+ {
+ "name": "RED_B",
+ "id": "2"
+ },
+ {
+ "name": "BLUE_A",
+ "id": "3"
+ },
+ {
+ "name": "BLUE_B",
+ "id": "4"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "400",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r4-link1": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r4-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r4-link1": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r4-link1": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "400",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r4-link2": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r4-link2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r4-link2": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r4-link2": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "400",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r4-link3": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r4-link3": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r4-link3": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r4-link3": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "400",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r4-link4": {}
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r4-link4": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r4-link4": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ },
+ "r3": {
+ "dest_link": {
+ "r4-link4": {
+ "route_maps": [{
+ "name": "rmap_global",
+ "direction": "in"
+ }]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ],
+ "route_maps": {
+ "rmap_global": [{
+ "action": "permit",
+ "set": {
+ "ipv6": {
+ "nexthop": "prefer-global"
+ }
+ }
+ }]
+ }
+ },
+ "red2": {
+ "links": {
+ "r3-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "r3-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"}
+ },
+ "vrfs":[
+ {
+ "name": "RED_A",
+ "id": "1"
+ },
+ {
+ "name": "RED_B",
+ "id": "2"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "500",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "red2-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "red2-link1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "500",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "red2-link2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "red2-link2": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "blue2": {
+ "links": {
+ "r3-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_A"},
+ "r3-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"}
+ },
+ "vrfs":[
+ {
+ "name": "BLUE_A",
+ "id": "1"
+ },
+ {
+ "name": "BLUE_B",
+ "id": "2"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "800",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "blue2-link1": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "blue2-link1": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "800",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "blue2-link2": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "blue2-link2": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+ }
+}
diff --git a/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py b/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py
new file mode 100755
index 0000000000..27c4430a52
--- /dev/null
+++ b/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py
@@ -0,0 +1,2012 @@
+#!/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:
+
+CHAOS_1:
+ Do a shut and no shut on connecting interface of DUT,
+ to see if all vrf instances clear their respective BGP tables
+ during the interface down and restores when interface brought
+kCHAOS_3:
+ VRF leaking - next-hop interface is flapping.
+CHAOS_5:
+ VRF - VLANs - Routing Table ID - combination testcase
+ on DUT.
+CHAOS_9:
+ Verify that all vrf instances fall back
+ to backup path, if primary link goes down.
+
+"""
+
+import os
+import sys
+import json
+import time
+import pytest
+from copy import deepcopy
+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, "../"))
+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 mininet.topo import Topo
+
+from lib.common_config import (
+ step,
+ verify_rib,
+ start_topology,
+ write_test_header,
+ check_address_types,
+ write_test_footer,
+ reset_config_on_routers,
+ create_route_maps,
+ shutdown_bringup_interface,
+ start_router_daemons,
+ kill_router_daemons,
+ create_static_routes,
+ create_vrf_cfg,
+ create_interfaces_cfg,
+ create_interface_in_kernel,
+ kill_mininet_routers_process,
+ get_frr_ipv6_linklocal,
+ check_router_status,
+ apply_raw_config,
+)
+
+from lib.topolog import logger
+from lib.bgp import clear_bgp, verify_bgp_rib, create_router_bgp, verify_bgp_convergence
+from lib.topojson import build_config_from_json, build_topo_from_json
+
+# Reading the data from JSON File for topology creation
+jsonFile = "{}/bgp_multi_vrf_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": "1.1.1.1/32", "ipv6": "1::1/128"}
+NETWORK1_2 = {"ipv4": "1.1.1.2/32", "ipv6": "1::2/128"}
+NETWORK2_1 = {"ipv4": "2.1.1.1/32", "ipv6": "2::1/128"}
+NETWORK2_2 = {"ipv4": "2.1.1.2/32", "ipv6": "2::2/128"}
+NETWORK3_1 = {"ipv4": "3.1.1.1/32", "ipv6": "3::1/128"}
+NETWORK3_2 = {"ipv4": "3.1.1.2/32", "ipv6": "3::2/128"}
+NETWORK4_1 = {"ipv4": "4.1.1.1/32", "ipv6": "4::1/128"}
+NETWORK4_2 = {"ipv4": "4.1.1.2/32", "ipv6": "4::2/128"}
+NETWORK9_1 = {"ipv4": "100.1.0.1/30", "ipv6": "100::1/126"}
+NETWORK9_2 = {"ipv4": "100.1.0.2/30", "ipv6": "100::2/126"}
+
+NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"}
+
+LOOPBACK_2 = {
+ "ipv4": "20.20.20.20/32",
+ "ipv6": "20::20:20/128",
+ "ipv4_mask": "255.255.255.255",
+ "ipv6_mask": None,
+}
+
+MAX_PATHS = 2
+KEEPALIVETIMER = 1
+HOLDDOWNTIMER = 3
+PREFERRED_NEXT_HOP = "link_local"
+
+
+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
+ """
+
+ 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.
+
+ # Kill stale mininet routers and process
+ kill_mininet_routers_process(tgen)
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start deamons and then start routers
+ start_topology(tgen)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, topo)
+
+ 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_vrf_with_multiple_links_p1(request):
+ """
+ CHAOS_9:
+ Verify that all vrf instances fall back
+ to backup path, if primary link goes down.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step(
+ "Configure BGP neighborships(IPv4+IPv6) between R1 and R4 "
+ "using exact same link IPs for all 4 VRFs."
+ )
+
+ topo_modify = deepcopy(topo)
+ build_config_from_json(tgen, topo_modify)
+
+ interfaces = ["link1", "link2", "link3", "link4"]
+ for interface in interfaces:
+ topo_modify["routers"]["r1"]["links"]["r4-{}".format(interface)][
+ "delete"
+ ] = True
+ topo_modify["routers"]["r4"]["links"]["r1-{}".format(interface)][
+ "delete"
+ ] = True
+
+ step("Build interface config from json")
+ create_interfaces_cfg(tgen, topo_modify["routers"])
+
+ interfaces = ["link1", "link2", "link3", "link4"]
+ for interface in interfaces:
+ del topo_modify["routers"]["r1"]["links"]["r4-{}".format(interface)]["delete"]
+ del topo_modify["routers"]["r4"]["links"]["r1-{}".format(interface)]["delete"]
+
+ r1_config = []
+ r4_config = []
+ for addr_type in ADDR_TYPES:
+ interfaces = ["link1", "link2", "link3", "link4"]
+ for interface in interfaces:
+ intf_name_r1 = topo_modify["routers"]["r1"]["links"][
+ "r4-{}".format(interface)
+ ]["interface"]
+ topo_modify["routers"]["r1"]["links"]["r4-{}".format(interface)][
+ addr_type
+ ] = NETWORK9_1[addr_type]
+
+ intf_name_r4 = topo_modify["routers"]["r4"]["links"][
+ "r1-{}".format(interface)
+ ]["interface"]
+ topo_modify["routers"]["r4"]["links"]["r1-{}".format(interface)][
+ addr_type
+ ] = NETWORK9_2[addr_type]
+
+ r1_config.append("interface {}".format(intf_name_r1))
+ r4_config.append("interface {}".format(intf_name_r4))
+ if addr_type == "ipv4":
+ r1_config.append("no ip address {}".format(NETWORK9_1[addr_type]))
+ r4_config.append("no ip address {}".format(NETWORK9_2[addr_type]))
+ else:
+ r1_config.append("no ipv6 address {}".format(NETWORK9_1[addr_type]))
+ r4_config.append("no ipv6 address {}".format(NETWORK9_2[addr_type]))
+
+ step("Build interface config from json")
+ create_interfaces_cfg(tgen, topo_modify["routers"])
+
+ step("Create bgp config")
+ result = create_router_bgp(tgen, topo_modify["routers"])
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify BGP convergence")
+
+ result = verify_bgp_convergence(tgen, topo_modify)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result)
+
+ step(
+ "Advertise below prefixes in BGP using static redistribution"
+ " for both vrfs (RED_A and BLUE_A) on router R2.."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ {
+ "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {}
+ for dut in ["r1"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ VRFS = ["RED_A", "RED_B", "BLUE_A", "BLUE_B"]
+ AS_NUM = [100, 100, 100, 100]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo_modify, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify routes are installed with same nexthop in different" " VRFs")
+
+ for addr_type in ADDR_TYPES:
+ dut = "r4"
+ _input_dict = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+
+ R1_NEXTHOP = topo_modify["routers"]["r1"]["links"]["r4-link1"][addr_type].split(
+ "/"
+ )[0]
+
+ result = verify_rib(tgen, addr_type, dut, _input_dict, next_hop=R1_NEXTHOP)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ _input_dict = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ }
+ ]
+ }
+ }
+
+ R1_NEXTHOP = topo_modify["routers"]["r1"]["links"]["r4-link1"][addr_type].split(
+ "/"
+ )[0]
+
+ result = verify_rib(tgen, addr_type, dut, _input_dict, next_hop=R1_NEXTHOP)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ _input_dict = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ }
+ ]
+ }
+ }
+
+ R1_NEXTHOP = topo_modify["routers"]["r1"]["links"]["r4-link1"][addr_type].split(
+ "/"
+ )[0]
+
+ result = verify_rib(tgen, addr_type, dut, _input_dict, next_hop=R1_NEXTHOP)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ _input_dict = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ }
+ ]
+ }
+ }
+
+ R1_NEXTHOP = topo_modify["routers"]["r1"]["links"]["r4-link1"][addr_type].split(
+ "/"
+ )[0]
+
+ result = verify_rib(tgen, addr_type, dut, _input_dict, next_hop=R1_NEXTHOP)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Configure a route-map on R3 to prepend as-path and apply"
+ " for neighbour router R2 in both vrfs, in inbound direction."
+ )
+
+ input_dict_4 = {
+ "r3": {
+ "route_maps": {
+ "ASP": [
+ {
+ "action": "permit",
+ "set": {"path": {"as_num": 123, "as_action": "prepend"}},
+ }
+ ]
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Apply route-map to neighbours")
+ step(
+ "Configure ECMP on router R3 using 'max-path' command for both"
+ " VRFs RED_A and BLUE_A."
+ )
+
+ input_dict_5 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "200",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {
+ "route_maps": [
+ {"name": "ASP", "direction": "in"}
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {
+ "route_maps": [
+ {"name": "ASP", "direction": "in"}
+ ]
+ }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3-link1": {
+ "route_maps": [
+ {
+ "name": "rmap_global",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "200",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link2": {
+ "route_maps": [
+ {"name": "ASP", "direction": "in"}
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link2": {
+ "route_maps": [
+ {"name": "ASP", "direction": "in"}
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "200",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link3": {
+ "route_maps": [
+ {"name": "ASP", "direction": "in"}
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link3": {
+ "route_maps": [
+ {"name": "ASP", "direction": "in"}
+ ]
+ }
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3-link3": {
+ "route_maps": [
+ {
+ "name": "rmap_global",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ },
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "200",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link4": {
+ "route_maps": [
+ {"name": "ASP", "direction": "in"}
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link4": {
+ "route_maps": [
+ {"name": "ASP", "direction": "in"}
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ ]
+ }
+ }
+
+ result = create_router_bgp(tgen, topo_modify, input_dict_5)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+ dut = "r3"
+ peer = "r2"
+ input_dict = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+
+ intf = topo_modify["routers"][peer]["links"]["r3-link1"]["interface"]
+ if addr_type == "ipv6" and "link_local" in PREFERRED_NEXT_HOP:
+ R2_NEXTHOP = get_frr_ipv6_linklocal(tgen, peer, intf=intf, vrf="RED_A")
+ else:
+ R2_NEXTHOP = topo_modify["routers"]["r2"]["links"]["r3-link1"][
+ addr_type
+ ].split("/")[0]
+
+ result = verify_rib(tgen, addr_type, dut, input_dict, next_hop=R2_NEXTHOP)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ input_dict = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "vrf": "BLUE_A",
+ }
+ ]
+ }
+ }
+
+ intf = topo["routers"][peer]["links"]["r3-link3"]["interface"]
+ if addr_type == "ipv6" and "link_local" in PREFERRED_NEXT_HOP:
+ R2_NEXTHOP = get_frr_ipv6_linklocal(tgen, peer, intf=intf, vrf="BLUE_A")
+ else:
+ R2_NEXTHOP = topo_modify["routers"]["r2"]["links"]["r3-link3"][
+ addr_type
+ ].split("/")[0]
+
+ result = verify_rib(tgen, addr_type, dut, input_dict, next_hop=R2_NEXTHOP)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Configure ECMP on router R3 using max-path command for"
+ " both VRFs RED_A and BLUE_A."
+ )
+
+ input_dict_7 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "200",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {"unicast": {"maximum_paths": {"ebgp": MAX_PATHS,}}},
+ "ipv6": {"unicast": {"maximum_paths": {"ebgp": MAX_PATHS,}}},
+ },
+ },
+ {
+ "local_as": "200",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {"unicast": {"maximum_paths": {"ebgp": MAX_PATHS,}}},
+ "ipv6": {"unicast": {"maximum_paths": {"ebgp": MAX_PATHS,}}},
+ },
+ },
+ ]
+ }
+ }
+
+ result = create_router_bgp(tgen, topo_modify, input_dict_7)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("R3 should install prefixes from both next-hops (R2 and R4)")
+
+ for addr_type in ADDR_TYPES:
+ dut = "r3"
+ peer = "r2"
+ input_dict = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+
+ intf = topo_modify["routers"][peer]["links"]["r3-link1"]["interface"]
+ if addr_type == "ipv6" and "link_local" in PREFERRED_NEXT_HOP:
+ R2_NEXTHOP = get_frr_ipv6_linklocal(tgen, peer, intf=intf, vrf="RED_A")
+ else:
+ R2_NEXTHOP = topo_modify["routers"]["r2"]["links"]["r3-link1"][
+ addr_type
+ ].split("/")[0]
+
+ result = verify_rib(tgen, addr_type, dut, input_dict, next_hop=R2_NEXTHOP)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ input_dict = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "vrf": "BLUE_A",
+ }
+ ]
+ }
+ }
+
+ intf = topo_modify["routers"][peer]["links"]["r3-link3"]["interface"]
+ if addr_type == "ipv6" and "link_local" in PREFERRED_NEXT_HOP:
+ R2_NEXTHOP = get_frr_ipv6_linklocal(tgen, peer, intf=intf, vrf="BLUE_A")
+ else:
+ R2_NEXTHOP = topo_modify["routers"]["r2"]["links"]["r3-link3"][
+ addr_type
+ ].split("/")[0]
+
+ result = verify_rib(tgen, addr_type, dut, input_dict, next_hop=R2_NEXTHOP)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step("Shutdown interface between R2 and R3 for vrfs RED_A and " "BLUE_A.")
+
+ intf1 = topo_modify["routers"]["r2"]["links"]["r3-link1"]["interface"]
+ intf2 = topo_modify["routers"]["r2"]["links"]["r3-link3"]["interface"]
+
+ interfaces = [intf1, intf2]
+ for intf in interfaces:
+ shutdown_bringup_interface(tgen, "r2", intf, False)
+
+ for addr_type in ADDR_TYPES:
+ dut = "r3"
+ peer = "r4"
+ input_dict = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+
+ R4_NEXTHOP = topo_modify["routers"]["r4"]["links"]["r3-link1"][addr_type].split(
+ "/"
+ )[0]
+
+ result = verify_rib(tgen, addr_type, dut, input_dict, next_hop=R4_NEXTHOP)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ input_dict = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "vrf": "BLUE_A",
+ }
+ ]
+ }
+ }
+
+ R4_NEXTHOP = topo_modify["routers"]["r4"]["links"]["r3-link3"][addr_type].split(
+ "/"
+ )[0]
+
+ result = verify_rib(tgen, addr_type, dut, input_dict, next_hop=R4_NEXTHOP)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step("Unshut the interfaces between R2 and R3 for vrfs RED_A and BLUE_A.")
+
+ for intf in interfaces:
+ shutdown_bringup_interface(tgen, "r2", intf, True)
+
+ for addr_type in ADDR_TYPES:
+ dut = "r3"
+ peer = "r2"
+ input_dict = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+
+ R4_NEXTHOP = topo_modify["routers"]["r4"]["links"]["r3-link1"][addr_type].split(
+ "/"
+ )[0]
+
+ result = verify_rib(tgen, addr_type, dut, input_dict, next_hop=R4_NEXTHOP)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ input_dict = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "vrf": "BLUE_A",
+ }
+ ]
+ }
+ }
+
+ R4_NEXTHOP = topo_modify["routers"]["r4"]["links"]["r3-link3"][addr_type].split(
+ "/"
+ )[0]
+
+ result = verify_rib(tgen, addr_type, dut, input_dict, next_hop=R4_NEXTHOP)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step("Remove route-map from R3 for vrfs RED_A and BLUE_A.")
+
+ input_dict_6 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "200",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {
+ "route_maps": [
+ {
+ "name": "ASP_ipv4",
+ "direction": "in",
+ "delete": True,
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {
+ "route_maps": [
+ {
+ "name": "ASP_ipv6",
+ "direction": "in",
+ "delete": True,
+ },
+ {
+ "name": "rmap_global",
+ "direction": "in",
+ },
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "200",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link3": {
+ "route_maps": [
+ {
+ "name": "ASP_ipv4",
+ "direction": "in",
+ "delete": True,
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link3": {
+ "route_maps": [
+ {
+ "name": "ASP_ipv6",
+ "direction": "in",
+ "delete": True,
+ },
+ {
+ "name": "rmap_global",
+ "direction": "in",
+ },
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ ]
+ }
+ }
+
+ result = create_router_bgp(tgen, topo_modify, input_dict_6)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+ dut = "r3"
+ input_dict = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+
+ R2_NEXTHOP = topo_modify["routers"]["r2"]["links"]["r3-link1"][addr_type].split(
+ "/"
+ )[0]
+
+ result = verify_rib(tgen, addr_type, dut, input_dict, next_hop=R2_NEXTHOP)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ input_dict = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "vrf": "BLUE_A",
+ }
+ ]
+ }
+ }
+
+ R2_NEXTHOP = topo_modify["routers"]["r2"]["links"]["r3-link3"][addr_type].split(
+ "/"
+ )[0]
+
+ result = verify_rib(tgen, addr_type, dut, input_dict, next_hop=R2_NEXTHOP)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step("Shutdown links between between R2 and R3 for vrfs RED_A and" " BLUE_A.")
+
+ for intf in interfaces:
+ shutdown_bringup_interface(tgen, "r2", intf, False)
+
+ for addr_type in ADDR_TYPES:
+ dut = "r3"
+ input_dict = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+
+ R4_NEXTHOP = topo_modify["routers"]["r4"]["links"]["r3-link1"][addr_type].split(
+ "/"
+ )[0]
+
+ result = verify_rib(tgen, addr_type, dut, input_dict, next_hop=R4_NEXTHOP)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ input_dict = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "vrf": "BLUE_A",
+ }
+ ]
+ }
+ }
+
+ R4_NEXTHOP = topo_modify["routers"]["r4"]["links"]["r3-link3"][addr_type].split(
+ "/"
+ )[0]
+
+ result = verify_rib(tgen, addr_type, dut, input_dict, next_hop=R4_NEXTHOP)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step("Bringup links between between R2 and R3 for vrfs RED_A and" " BLUE_A.")
+
+ for intf in interfaces:
+ shutdown_bringup_interface(tgen, "r2", intf, True)
+
+ step("Deleting manualy assigned ip address from router r1 and r4 interfaces")
+ raw_config = {"r1": {"raw_config": r1_config}, "r4": {"raw_config": r4_config}}
+ result = apply_raw_config(tgen, raw_config)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_shut_noshut_p1(request):
+ """
+ CHAOS_1:
+ Do a shut and no shut on connecting interface of DUT,
+ to see if all vrf instances clear their respective BGP tables
+ during the interface down and restores when interface brought
+ back up again.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step("Build interface config from json")
+ create_interfaces_cfg(tgen, topo["routers"])
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ step(
+ "Advertise unique prefixes in BGP using static redistribution"
+ " for both vrfs (RED_A and RED_B) on router RED_1."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Advertise unique prefixes in BGP using static redistribution"
+ " for both vrfs (BLUE_A and BLUE_B) on router BLUE_1."
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {}
+ for dut in ["red1", "blue1"]:
+ temp = {dut: {"bgp": []}}
+ input_dict_3.update(temp)
+
+ if "red" in dut:
+ VRFS = ["RED_A", "RED_B"]
+ AS_NUM = [500, 500]
+ elif "blue" in dut:
+ VRFS = ["BLUE_A", "BLUE_B"]
+ AS_NUM = [800, 800]
+
+ for vrf, as_num in zip(VRFS, AS_NUM):
+ temp[dut]["bgp"].append(
+ {
+ "local_as": as_num,
+ "vrf": vrf,
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ )
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Api call to modfiy BGP timerse")
+
+ input_dict_4 = {
+ "r1": {
+ "bgp": [
+ {
+ "local_as": "100",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link1": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link2": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link2": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link3": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link3": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link4": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r1-link4": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ ]
+ },
+ "r2": {
+ "bgp": [
+ {
+ "local_as": "100",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link1": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "RED_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link2": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link2": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link3": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link3": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ {
+ "local_as": "100",
+ "vrf": "BLUE_B",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link4": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {
+ "dest_link": {
+ "r2-link4": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ },
+ ]
+ },
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+ clear_bgp(tgen, addr_type, "r1", vrf=["RED_A", "RED_B", "BLUE_A", "BLUE_B"])
+
+ clear_bgp(tgen, addr_type, "r2", vrf=["RED_A", "RED_B", "BLUE_A", "BLUE_B"])
+
+ step("Shut down connecting interface between R1<<>>R2 on R1.")
+ step("Repeat step-3 and step-4 10 times.")
+
+ for count in range(1, 2):
+ step("Iteration {}".format(count))
+ step("Shut down connecting interface between R1<<>>R2 on R1.")
+
+ intf1 = topo["routers"]["r1"]["links"]["r2-link1"]["interface"]
+ intf2 = topo["routers"]["r1"]["links"]["r2-link2"]["interface"]
+ intf3 = topo["routers"]["r1"]["links"]["r2-link3"]["interface"]
+ intf4 = topo["routers"]["r1"]["links"]["r2-link4"]["interface"]
+
+ interfaces = [intf1, intf2, intf3, intf4]
+ for intf in interfaces:
+ shutdown_bringup_interface(tgen, "r1", intf, False)
+
+ step(
+ "On R2, all BGP peering in respective vrf instances go down"
+ " when the interface is shut"
+ )
+
+ step("Sleeping for holddowntimer+1 sec..")
+ sleep(HOLDDOWNTIMER + 1)
+
+ result = verify_bgp_convergence(tgen, topo, expected=False)
+ assert result is not True, "Testcase {} : Failed \n "
+ "Expected Behaviour: BGP will not be converged \n "
+ "Error {}".format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+ dut = "r2"
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]]
+ + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]]
+ + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]]
+ + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]]
+ + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False)
+ assert result is not True, "Testcase {} : Failed \n "
+ " Expected Behaviour: Routes are flushed out \n "
+ "Error {}".format(tc_name, result)
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2, expected=False)
+ assert result is not True, "Testcase {} : Failed \n "
+ " Expected Behaviour: Routes are flushed out \n "
+ "Error {}".format(tc_name, result)
+
+ step("Bring up connecting interface between R1<<>>R2 on R1.")
+ for intf in interfaces:
+ shutdown_bringup_interface(tgen, "r1", intf, True)
+
+ step(
+ "R2 restores BGP peering and routing tables in all vrf "
+ "instances when interface brought back up again"
+ )
+
+ result = verify_bgp_convergence(tgen, topo)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "r2"
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]]
+ + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]]
+ + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_B",
+ },
+ ]
+ }
+ }
+
+ input_dict_2 = {
+ "blue1": {
+ "static_routes": [
+ {
+ "network": [NETWORK1_1[addr_type]]
+ + [NETWORK1_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_A",
+ },
+ {
+ "network": [NETWORK2_1[addr_type]]
+ + [NETWORK2_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE_B",
+ },
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_2)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_vrf_vlan_routing_table_p1(request):
+ """
+ CHAOS_5:
+ VRF - VLANs - Routing Table ID - combination testcase
+ on DUT.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step(
+ "Advertise unique prefixes(IPv4+IPv6) in BGP using"
+ " network command for vrf RED_A on router R2"
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK1_1[addr_type],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {
+ "r2": {
+ "bgp": [
+ {
+ "local_as": "100",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ ]
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that static routes(IPv4+IPv6) is overridden and doesn't"
+ " have duplicate entries within VRF RED_A on router RED-1"
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "r3"
+ input_dict_1 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK1_1[addr_type],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step("Api call to modfiy BGP timerse")
+
+ input_dict_4 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "200",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ }
+ ]
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ for addr_type in ADDR_TYPES:
+ clear_bgp(tgen, addr_type, "r3", vrf=["RED_A"])
+
+ step("Repeat for 5 times.")
+
+ for count in range(1, 2):
+ step("Iteration {}..".format(count))
+ step("Delete a specific VRF instance(RED_A) from router R3")
+
+ input_dict = {"r3": {"vrfs": [{"name": "RED_A", "id": "1", "delete": True}]}}
+
+ result = create_vrf_cfg(tgen, input_dict)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step("Sleeping for holdowntimer+1 sec..")
+ sleep(HOLDDOWNTIMER + 1)
+
+ for addr_type in ADDR_TYPES:
+ dut = "r3"
+ input_dict_1 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK1_1[addr_type],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False)
+ assert (
+ result is not True
+ ), "Testcase {} : Failed \n Expected Behaviour: Routes are"
+ " cleaned \n Error {}".format(tc_name, result)
+
+ step("Add/reconfigure the same VRF instance again")
+
+ result = create_vrf_cfg(tgen, {"r3": topo["routers"]["r3"]})
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step(
+ "After deleting VRFs ipv6 addresses wil be deleted from kernel "
+ " Adding back ipv6 addresses"
+ )
+
+ dut = "r3"
+ vrf = "RED_A"
+
+ for c_link, c_data in topo["routers"][dut]["links"].items():
+ if c_data["vrf"] != vrf:
+ continue
+
+ intf_name = c_data["interface"]
+ intf_ipv6 = c_data["ipv6"]
+
+ create_interface_in_kernel(
+ tgen, dut, intf_name, intf_ipv6, vrf, create=False
+ )
+
+ step("Sleeping for holdowntimer+1 sec..")
+ sleep(HOLDDOWNTIMER + 1)
+
+ for addr_type in ADDR_TYPES:
+ dut = "r3"
+ input_dict_1 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK1_1[addr_type],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+
+ result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_vrf_route_leaking_next_hop_interface_flapping_p1(request):
+ """
+ CHAOS_3:
+ VRF leaking - next-hop interface is flapping.
+ """
+
+ tgen = get_topogen()
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ reset_config_on_routers(tgen)
+
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+
+ step("Create loopback interface")
+
+ for addr_type in ADDR_TYPES:
+ create_interface_in_kernel(
+ tgen,
+ "red1",
+ "loopback2",
+ LOOPBACK_2[addr_type],
+ "RED_B",
+ LOOPBACK_2["{}_mask".format(addr_type)],
+ )
+
+ intf_red1_r11 = topo["routers"]["red1"]["links"]["r1-link2"]["interface"]
+ for addr_type in ADDR_TYPES:
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": LOOPBACK_2[addr_type],
+ "interface": intf_red1_r11,
+ "nexthop_vrf": "RED_B",
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Redistribute static..")
+
+ input_dict_3 = {
+ "red1": {
+ "bgp": [
+ {
+ "local_as": "500",
+ "vrf": "RED_A",
+ "address_family": {
+ "ipv4": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ "ipv6": {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ },
+ },
+ }
+ ]
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("VRF RED_A should install a route for vrf RED_B's " "loopback ip.")
+ for addr_type in ADDR_TYPES:
+ dut = "red1"
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": LOOPBACK_2[addr_type],
+ "interface": intf_red1_r11,
+ "nexthop_vrf": "RED_B",
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_1, protocol="static")
+ assert result is True, "Testcase {} : Failed \n Error {}".format(
+ tc_name, result
+ )
+
+ step("Repeat step-2 to 4 at least 5 times")
+
+ for count in range(1, 2):
+ intf1 = topo["routers"]["red1"]["links"]["r1-link2"]["interface"]
+
+ step(
+ "Iteration {}: Shutdown interface {} on router"
+ "RED_1.".format(count, intf1)
+ )
+ shutdown_bringup_interface(tgen, "red1", intf1, False)
+
+ step("Verify that RED_A removes static route from routing " "table.")
+
+ for addr_type in ADDR_TYPES:
+ dut = "red1"
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": LOOPBACK_2[addr_type],
+ "interface": intf_red1_r11,
+ "nexthop_vrf": "RED_B",
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+
+ result = verify_rib(
+ tgen, addr_type, dut, input_dict_1, protocol="static", expected=False
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n Expected Behaviour: Routes are"
+ " not present Error {}".format(tc_name, result)
+ )
+
+ step("Bring up interface {} on router RED_1 again.".format(intf1))
+ shutdown_bringup_interface(tgen, "red1", intf1, True)
+
+ step(
+ "Verify that RED_A reinstalls static route pointing to "
+ "RED_B's IP in routing table again"
+ )
+
+ for addr_type in ADDR_TYPES:
+ dut = "red1"
+ input_dict_1 = {
+ "red1": {
+ "static_routes": [
+ {
+ "network": LOOPBACK_2[addr_type],
+ "interface": intf_red1_r11,
+ "nexthop_vrf": "RED_B",
+ "vrf": "RED_A",
+ }
+ ]
+ }
+ }
+
+ result = verify_rib(tgen, addr_type, dut, input_dict_1, protocol="static")
+ 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/conftest.py b/tests/topotests/conftest.py
index d46c52a4c4..04e9961f10 100755
--- a/tests/topotests/conftest.py
+++ b/tests/topotests/conftest.py
@@ -48,7 +48,7 @@ def pytest_assertrepr_compare(op, left, right):
if not isinstance(json_result, json_cmp_result):
return None
- return json_result.errors
+ return json_result.gen_report()
def pytest_configure(config):
diff --git a/tests/topotests/isis-sr-topo1/__init__.py b/tests/topotests/isis-sr-topo1/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/__init__.py
diff --git a/tests/topotests/isis-sr-topo1/rt1/isisd.conf b/tests/topotests/isis-sr-topo1/rt1/isisd.conf
new file mode 100644
index 0000000000..70ae1b07f5
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/isisd.conf
@@ -0,0 +1,30 @@
+password 1
+hostname rt1
+log file isisd.log
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+debug isis sr-events
+debug isis lsp-gen
+!
+interface lo
+ ip router isis 1
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-sw1
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+!
+router isis 1
+ net 49.0000.0000.0000.0001.00
+ is-type level-1
+ topology ipv6-unicast
+ segment-routing on
+ segment-routing global-block 16000 23999
+ segment-routing node-msd 8
+ segment-routing prefix 1.1.1.1/32 index 10
+ segment-routing prefix 2001:db8:1000::1/128 index 11
+!
diff --git a/tests/topotests/isis-sr-topo1/rt1/step1/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt1/step1/show_ip_route.ref
new file mode 100644
index 0000000000..6b4a59011a
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step1/show_ip_route.ref
@@ -0,0 +1,294 @@
+{
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17050
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17060
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ },
+ {
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt1/step1/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt1/step1/show_ipv6_route.ref
new file mode 100644
index 0000000000..c507688f5b
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step1/show_ipv6_route.ref
@@ -0,0 +1,121 @@
+{
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17051
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17061
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt1/step1/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt1/step1/show_mpls_table.ref
new file mode 100644
index 0000000000..773f5e3d43
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step1/show_mpls_table.ref
@@ -0,0 +1,134 @@
+{
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17050,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17051,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16060":{
+ "inLabel":16060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17060,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16061":{
+ "inLabel":16061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-sw1"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17061,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt1/step1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt1/step1/show_yang_interface_isis_adjacencies.ref
new file mode 100644
index 0000000000..69dcc91b1d
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step1/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1,34 @@
+{
+ "frr-interface:lib": {
+ "interface": [
+ {
+ "name": "eth-sw1",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0003",
+ "neighbor-extended-circuit-id": 2,
+ "hold-timer": 9,
+ "neighbor-priority": 64,
+ "state": "up"
+ },
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0002",
+ "neighbor-extended-circuit-id": 2,
+ "hold-timer": 9,
+ "neighbor-priority": 64,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt1/step10/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt1/step10/show_ip_route.ref
new file mode 100644
index 0000000000..6b34d5e4ff
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step10/show_ip_route.ref
@@ -0,0 +1,287 @@
+{
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17050
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17060
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ },
+ {
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt1/step10/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt1/step10/show_ipv6_route.ref
new file mode 100644
index 0000000000..c507688f5b
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step10/show_ipv6_route.ref
@@ -0,0 +1,121 @@
+{
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17051
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17061
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt1/step10/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt1/step10/show_mpls_table.ref
new file mode 100644
index 0000000000..25a48c2bfc
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step10/show_mpls_table.ref
@@ -0,0 +1,156 @@
+{
+ "16010":{
+ "inLabel":16010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16011":{
+ "inLabel":16011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17050,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17051,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16060":{
+ "inLabel":16060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17060,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16061":{
+ "inLabel":16061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-sw1"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17061,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt1/step10/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt1/step10/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..0879b84d23
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step10/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step1/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt1/step2/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt1/step2/show_ip_route.ref
new file mode 100644
index 0000000000..6b34d5e4ff
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step2/show_ip_route.ref
@@ -0,0 +1,287 @@
+{
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17050
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17060
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ },
+ {
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt1/step2/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt1/step2/show_ipv6_route.ref
new file mode 100644
index 0000000000..c507688f5b
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step2/show_ipv6_route.ref
@@ -0,0 +1,121 @@
+{
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17051
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17061
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt1/step2/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt1/step2/show_mpls_table.ref
new file mode 100644
index 0000000000..773f5e3d43
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step2/show_mpls_table.ref
@@ -0,0 +1,134 @@
+{
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17050,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17051,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16060":{
+ "inLabel":16060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17060,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16061":{
+ "inLabel":16061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-sw1"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17061,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt1/step2/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt1/step2/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..0879b84d23
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step2/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step1/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt1/step3/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt1/step3/show_ip_route.ref
new file mode 100644
index 0000000000..05a8498693
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step3/show_ip_route.ref
@@ -0,0 +1,254 @@
+{
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17050
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ },
+ {
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt1/step3/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt1/step3/show_ipv6_route.ref
new file mode 100644
index 0000000000..d50952c6c4
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step3/show_ipv6_route.ref
@@ -0,0 +1,90 @@
+{
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17051
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt1/step3/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt1/step3/show_mpls_table.ref
new file mode 100644
index 0000000000..73f517a6e5
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step3/show_mpls_table.ref
@@ -0,0 +1,98 @@
+{
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17050,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17051,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt1/step3/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt1/step3/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..0879b84d23
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step3/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step1/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt1/step4/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt1/step4/show_ip_route.ref
new file mode 100644
index 0000000000..6b34d5e4ff
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step4/show_ip_route.ref
@@ -0,0 +1,287 @@
+{
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17050
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17060
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ },
+ {
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt1/step4/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt1/step4/show_ipv6_route.ref
new file mode 100644
index 0000000000..c507688f5b
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step4/show_ipv6_route.ref
@@ -0,0 +1,121 @@
+{
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17051
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17061
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt1/step4/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt1/step4/show_mpls_table.ref
new file mode 100644
index 0000000000..ac39920ee5
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step4/show_mpls_table.ref
@@ -0,0 +1,134 @@
+{
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17050,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17051,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16060":{
+ "inLabel":16060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17060,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16061":{
+ "inLabel":16061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17061,
+ "installed":true,
+ "interface":"eth-sw1"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt1/step4/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt1/step4/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..0879b84d23
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step4/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step1/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt1/step5/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt1/step5/show_ip_route.ref
new file mode 100644
index 0000000000..59213686f2
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step5/show_ip_route.ref
@@ -0,0 +1,281 @@
+{
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17050
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ },
+ {
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt1/step5/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt1/step5/show_ipv6_route.ref
new file mode 100644
index 0000000000..cdfae284ba
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step5/show_ipv6_route.ref
@@ -0,0 +1,115 @@
+{
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17051
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt1/step5/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt1/step5/show_mpls_table.ref
new file mode 100644
index 0000000000..73f517a6e5
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step5/show_mpls_table.ref
@@ -0,0 +1,98 @@
+{
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17050,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17051,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt1/step5/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt1/step5/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..0879b84d23
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step5/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step1/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt1/step6/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt1/step6/show_ip_route.ref
new file mode 100644
index 0000000000..6b34d5e4ff
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step6/show_ip_route.ref
@@ -0,0 +1,287 @@
+{
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17050
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17060
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ },
+ {
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt1/step6/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt1/step6/show_ipv6_route.ref
new file mode 100644
index 0000000000..c507688f5b
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step6/show_ipv6_route.ref
@@ -0,0 +1,121 @@
+{
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17051
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17061
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt1/step6/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt1/step6/show_mpls_table.ref
new file mode 100644
index 0000000000..773f5e3d43
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step6/show_mpls_table.ref
@@ -0,0 +1,134 @@
+{
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17050,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17051,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16060":{
+ "inLabel":16060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17060,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16061":{
+ "inLabel":16061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-sw1"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17061,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt1/step6/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt1/step6/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..0879b84d23
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step6/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step1/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt1/step7/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt1/step7/show_ip_route.ref
new file mode 100644
index 0000000000..6b34d5e4ff
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step7/show_ip_route.ref
@@ -0,0 +1,287 @@
+{
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17050
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17060
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ },
+ {
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt1/step7/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt1/step7/show_ipv6_route.ref
new file mode 100644
index 0000000000..c507688f5b
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step7/show_ipv6_route.ref
@@ -0,0 +1,121 @@
+{
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17051
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17061
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt1/step7/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt1/step7/show_mpls_table.ref
new file mode 100644
index 0000000000..773f5e3d43
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step7/show_mpls_table.ref
@@ -0,0 +1,134 @@
+{
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17050,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17051,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16060":{
+ "inLabel":16060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17060,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16061":{
+ "inLabel":16061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-sw1"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17061,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt1/step7/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt1/step7/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..0879b84d23
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step7/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step1/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt1/step8/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt1/step8/show_ip_route.ref
new file mode 100644
index 0000000000..6b34d5e4ff
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step8/show_ip_route.ref
@@ -0,0 +1,287 @@
+{
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17050
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17060
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ },
+ {
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt1/step8/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt1/step8/show_ipv6_route.ref
new file mode 100644
index 0000000000..c507688f5b
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step8/show_ipv6_route.ref
@@ -0,0 +1,121 @@
+{
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17051
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17061
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt1/step8/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt1/step8/show_mpls_table.ref
new file mode 100644
index 0000000000..773f5e3d43
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step8/show_mpls_table.ref
@@ -0,0 +1,134 @@
+{
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17050,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17051,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16060":{
+ "inLabel":16060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17060,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16061":{
+ "inLabel":16061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-sw1"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17061,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt1/step8/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt1/step8/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..0879b84d23
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step8/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step1/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt1/step9/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt1/step9/show_ip_route.ref
new file mode 100644
index 0000000000..6b34d5e4ff
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step9/show_ip_route.ref
@@ -0,0 +1,287 @@
+{
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17050
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17060
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ },
+ {
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt1/step9/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt1/step9/show_ipv6_route.ref
new file mode 100644
index 0000000000..c507688f5b
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step9/show_ipv6_route.ref
@@ -0,0 +1,121 @@
+{
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17051
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17061
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt1/step9/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt1/step9/show_mpls_table.ref
new file mode 100644
index 0000000000..25a48c2bfc
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step9/show_mpls_table.ref
@@ -0,0 +1,156 @@
+{
+ "16010":{
+ "inLabel":16010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16011":{
+ "inLabel":16011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17050,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17051,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16060":{
+ "inLabel":16060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17060,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16061":{
+ "inLabel":16061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-sw1"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17061,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt1/step9/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt1/step9/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..0879b84d23
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/step9/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step1/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt1/zebra.conf b/tests/topotests/isis-sr-topo1/rt1/zebra.conf
new file mode 100644
index 0000000000..9d71d3005f
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt1/zebra.conf
@@ -0,0 +1,19 @@
+log file zebra.log
+!
+hostname rt1
+!
+debug zebra kernel
+debug zebra packet
+debug zebra mpls
+!
+interface lo
+ ip address 1.1.1.1/32
+ ipv6 address 2001:db8:1000::1/128
+!
+interface eth-sw1
+ ip address 10.0.1.1/24
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-sr-topo1/rt2/isisd.conf b/tests/topotests/isis-sr-topo1/rt2/isisd.conf
new file mode 100644
index 0000000000..733f26bc62
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/isisd.conf
@@ -0,0 +1,41 @@
+hostname rt2
+log file isisd.log
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+debug isis sr-events
+debug isis lsp-gen
+!
+interface lo
+ ip router isis 1
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-sw1
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+!
+interface eth-rt4-1
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+!
+interface eth-rt4-2
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+!
+router isis 1
+ net 49.0000.0000.0000.0002.00
+ is-type level-1
+ topology ipv6-unicast
+ segment-routing on
+ segment-routing global-block 16000 23999
+ segment-routing node-msd 8
+ segment-routing prefix 2.2.2.2/32 index 20 no-php-flag
+ segment-routing prefix 2001:db8:1000::2/128 index 21 no-php-flag
+!
diff --git a/tests/topotests/isis-sr-topo1/rt2/step1/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt2/step1/show_ip_route.ref
new file mode 100644
index 0000000000..be037aba8b
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step1/show_ip_route.ref
@@ -0,0 +1,347 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 3
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17050
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true,
+ "labels":[
+ 16050
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true,
+ "labels":[
+ 16050
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ },
+ {
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1"
+ },
+ {
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2"
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt2/step1/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt2/step1/show_ipv6_route.ref
new file mode 100644
index 0000000000..a888198ac8
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step1/show_ipv6_route.ref
@@ -0,0 +1,148 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 3
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-1",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-2",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-1",
+ "active":true,
+ "labels":[
+ 16051
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-2",
+ "active":true,
+ "labels":[
+ 16051
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17051
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-1",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-2",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt2/step1/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt2/step1/show_mpls_table.ref
new file mode 100644
index 0000000000..42fde2d77f
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step1/show_mpls_table.ref
@@ -0,0 +1,192 @@
+{
+ "16010":{
+ "inLabel":16010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+ "nexthop":"10.0.1.1"
+ }
+ ]
+ },
+ "16011":{
+ "inLabel":16011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.3.4"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.2.4"
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-rt4-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-rt4-1"
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17050,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16050,
+ "installed":true,
+ "nexthop":"10.0.3.4"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16050,
+ "installed":true,
+ "nexthop":"10.0.2.4"
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17051,
+ "installed":true,
+ "interface":"eth-sw1"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16051,
+ "installed":true,
+ "interface":"eth-rt4-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16051,
+ "installed":true,
+ "interface":"eth-rt4-1"
+ }
+ ]
+ },
+ "16060":{
+ "inLabel":16060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.3.4"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.2.4"
+ }
+ ]
+ },
+ "16061":{
+ "inLabel":16061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-rt4-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-rt4-1"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt2/step1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt2/step1/show_yang_interface_isis_adjacencies.ref
new file mode 100644
index 0000000000..be018fd59f
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step1/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1,74 @@
+{
+ "frr-interface:lib": {
+ "interface": [
+ {
+ "name": "eth-rt4-1",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0004",
+ "neighbor-extended-circuit-id": 0,
+ "hold-timer": 9,
+ "neighbor-priority": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "name": "eth-rt4-2",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0004",
+ "neighbor-extended-circuit-id": 0,
+ "hold-timer": 9,
+ "neighbor-priority": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "name": "eth-sw1",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0003",
+ "neighbor-extended-circuit-id": 2,
+ "hold-timer": 9,
+ "neighbor-priority": 64,
+ "state": "up"
+ },
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0001",
+ "neighbor-extended-circuit-id": 2,
+ "hold-timer": 9,
+ "neighbor-priority": 64,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt2/step10/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt2/step10/show_ip_route.ref
new file mode 100644
index 0000000000..33fbdba28f
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step10/show_ip_route.ref
@@ -0,0 +1,259 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16010
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17050
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ },
+ {
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2"
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt2/step10/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt2/step10/show_ipv6_route.ref
new file mode 100644
index 0000000000..19837bc700
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step10/show_ipv6_route.ref
@@ -0,0 +1,130 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16011
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-1",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-2",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17051
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-1",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-2",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt2/step10/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt2/step10/show_mpls_table.ref
new file mode 100644
index 0000000000..29ec55a589
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step10/show_mpls_table.ref
@@ -0,0 +1,156 @@
+{
+ "16010":{
+ "inLabel":16010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16010,
+ "installed":true,
+ "nexthop":"10.0.1.1"
+ }
+ ]
+ },
+ "16011":{
+ "inLabel":16011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16011,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.3.4"
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-rt4-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-rt4-1"
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17050,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17051,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16060":{
+ "inLabel":16060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.3.4"
+ }
+ ]
+ },
+ "16061":{
+ "inLabel":16061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-rt4-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-rt4-1"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt2/step10/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt2/step10/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..0879b84d23
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step10/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step1/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt2/step2/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt2/step2/show_ip_route.ref
new file mode 100644
index 0000000000..a110c51077
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step2/show_ip_route.ref
@@ -0,0 +1,320 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 3
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17050
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ },
+ {
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1"
+ },
+ {
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2"
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt2/step2/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt2/step2/show_ipv6_route.ref
new file mode 100644
index 0000000000..cb426897ce
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step2/show_ipv6_route.ref
@@ -0,0 +1,130 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 3
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-1",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-2",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17051
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-1",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-2",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt2/step2/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt2/step2/show_mpls_table.ref
new file mode 100644
index 0000000000..118ec89b5c
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step2/show_mpls_table.ref
@@ -0,0 +1,168 @@
+{
+ "16010":{
+ "inLabel":16010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+ "nexthop":"10.0.1.1"
+ }
+ ]
+ },
+ "16011":{
+ "inLabel":16011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.3.4"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.2.4"
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-rt4-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-rt4-1"
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17050,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17051,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16060":{
+ "inLabel":16060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.3.4"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.2.4"
+ }
+ ]
+ },
+ "16061":{
+ "inLabel":16061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-rt4-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-rt4-1"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt2/step2/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt2/step2/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..0879b84d23
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step2/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step1/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt2/step3/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt2/step3/show_ip_route.ref
new file mode 100644
index 0000000000..d31affeb59
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step3/show_ip_route.ref
@@ -0,0 +1,273 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 3
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17050
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ },
+ {
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1"
+ },
+ {
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2"
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt2/step3/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt2/step3/show_ipv6_route.ref
new file mode 100644
index 0000000000..d92df1918c
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step3/show_ipv6_route.ref
@@ -0,0 +1,99 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 3
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-1",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-2",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17051
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt2/step3/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt2/step3/show_mpls_table.ref
new file mode 100644
index 0000000000..f1e18be26b
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step3/show_mpls_table.ref
@@ -0,0 +1,132 @@
+{
+ "16010":{
+ "inLabel":16010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+ "nexthop":"10.0.1.1"
+ }
+ ]
+ },
+ "16011":{
+ "inLabel":16011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.3.4"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.2.4"
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-rt4-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-rt4-1"
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17050,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17051,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt2/step3/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt2/step3/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..0879b84d23
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step3/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step1/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt2/step4/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt2/step4/show_ip_route.ref
new file mode 100644
index 0000000000..a110c51077
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step4/show_ip_route.ref
@@ -0,0 +1,320 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 3
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17050
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ },
+ {
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1"
+ },
+ {
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2"
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt2/step4/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt2/step4/show_ipv6_route.ref
new file mode 100644
index 0000000000..cb426897ce
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step4/show_ipv6_route.ref
@@ -0,0 +1,130 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 3
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-1",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-2",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17051
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-1",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-2",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt2/step4/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt2/step4/show_mpls_table.ref
new file mode 100644
index 0000000000..118ec89b5c
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step4/show_mpls_table.ref
@@ -0,0 +1,168 @@
+{
+ "16010":{
+ "inLabel":16010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+ "nexthop":"10.0.1.1"
+ }
+ ]
+ },
+ "16011":{
+ "inLabel":16011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.3.4"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.2.4"
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-rt4-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-rt4-1"
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17050,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17051,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16060":{
+ "inLabel":16060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.3.4"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.2.4"
+ }
+ ]
+ },
+ "16061":{
+ "inLabel":16061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-rt4-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-rt4-1"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt2/step4/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt2/step4/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..0879b84d23
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step4/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step1/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt2/step5/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt2/step5/show_ip_route.ref
new file mode 100644
index 0000000000..f378e41d8d
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step5/show_ip_route.ref
@@ -0,0 +1,314 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 3
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17050
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ },
+ {
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1"
+ },
+ {
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2"
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt2/step5/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt2/step5/show_ipv6_route.ref
new file mode 100644
index 0000000000..d63e7ceba5
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step5/show_ipv6_route.ref
@@ -0,0 +1,124 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 3
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-1",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-2",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17051
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt2/step5/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt2/step5/show_mpls_table.ref
new file mode 100644
index 0000000000..f1e18be26b
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step5/show_mpls_table.ref
@@ -0,0 +1,132 @@
+{
+ "16010":{
+ "inLabel":16010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+ "nexthop":"10.0.1.1"
+ }
+ ]
+ },
+ "16011":{
+ "inLabel":16011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.3.4"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.2.4"
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-rt4-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-rt4-1"
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17050,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17051,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt2/step5/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt2/step5/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..0879b84d23
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step5/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step1/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt2/step6/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt2/step6/show_ip_route.ref
new file mode 100644
index 0000000000..a110c51077
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step6/show_ip_route.ref
@@ -0,0 +1,320 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 3
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17050
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ },
+ {
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1"
+ },
+ {
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2"
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt2/step6/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt2/step6/show_ipv6_route.ref
new file mode 100644
index 0000000000..cb426897ce
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step6/show_ipv6_route.ref
@@ -0,0 +1,130 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 3
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-1",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-2",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17051
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-1",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-2",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt2/step6/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt2/step6/show_mpls_table.ref
new file mode 100644
index 0000000000..118ec89b5c
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step6/show_mpls_table.ref
@@ -0,0 +1,168 @@
+{
+ "16010":{
+ "inLabel":16010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+ "nexthop":"10.0.1.1"
+ }
+ ]
+ },
+ "16011":{
+ "inLabel":16011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.3.4"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.2.4"
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-rt4-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-rt4-1"
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17050,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17051,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16060":{
+ "inLabel":16060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.3.4"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.2.4"
+ }
+ ]
+ },
+ "16061":{
+ "inLabel":16061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-rt4-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-rt4-1"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt2/step6/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt2/step6/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..0879b84d23
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step6/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step1/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt2/step7/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt2/step7/show_ip_route.ref
new file mode 100644
index 0000000000..a9b086a248
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step7/show_ip_route.ref
@@ -0,0 +1,317 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17050
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ },
+ {
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1"
+ },
+ {
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2"
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt2/step7/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt2/step7/show_ipv6_route.ref
new file mode 100644
index 0000000000..1c61f91451
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step7/show_ipv6_route.ref
@@ -0,0 +1,127 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-1",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-2",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17051
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-1",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-2",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt2/step7/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt2/step7/show_mpls_table.ref
new file mode 100644
index 0000000000..0f0d24bbfb
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step7/show_mpls_table.ref
@@ -0,0 +1,144 @@
+{
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.3.4"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.2.4"
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-rt4-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-rt4-1"
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17050,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17051,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16060":{
+ "inLabel":16060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.3.4"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.2.4"
+ }
+ ]
+ },
+ "16061":{
+ "inLabel":16061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-rt4-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-rt4-1"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt2/step7/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt2/step7/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..0879b84d23
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step7/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step1/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt2/step8/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt2/step8/show_ip_route.ref
new file mode 100644
index 0000000000..a110c51077
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step8/show_ip_route.ref
@@ -0,0 +1,320 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 3
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17050
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ },
+ {
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1"
+ },
+ {
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2"
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt2/step8/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt2/step8/show_ipv6_route.ref
new file mode 100644
index 0000000000..cb426897ce
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step8/show_ipv6_route.ref
@@ -0,0 +1,130 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 3
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-1",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-2",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17051
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-1",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-2",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt2/step8/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt2/step8/show_mpls_table.ref
new file mode 100644
index 0000000000..118ec89b5c
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step8/show_mpls_table.ref
@@ -0,0 +1,168 @@
+{
+ "16010":{
+ "inLabel":16010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+ "nexthop":"10.0.1.1"
+ }
+ ]
+ },
+ "16011":{
+ "inLabel":16011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.3.4"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.2.4"
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-rt4-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-rt4-1"
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17050,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17051,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16060":{
+ "inLabel":16060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.3.4"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.2.4"
+ }
+ ]
+ },
+ "16061":{
+ "inLabel":16061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-rt4-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-rt4-1"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt2/step8/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt2/step8/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..0879b84d23
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step8/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step1/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt2/step9/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt2/step9/show_ip_route.ref
new file mode 100644
index 0000000000..2e4c20257f
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step9/show_ip_route.ref
@@ -0,0 +1,320 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16010
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17050
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ },
+ {
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1"
+ },
+ {
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2"
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.2.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4-2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt2/step9/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt2/step9/show_ipv6_route.ref
new file mode 100644
index 0000000000..19837bc700
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step9/show_ipv6_route.ref
@@ -0,0 +1,130 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16011
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-1",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-2",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 17051
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-1",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4-2",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt2/step9/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt2/step9/show_mpls_table.ref
new file mode 100644
index 0000000000..7c910fc6f6
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step9/show_mpls_table.ref
@@ -0,0 +1,168 @@
+{
+ "16010":{
+ "inLabel":16010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16010,
+ "installed":true,
+ "nexthop":"10.0.1.1"
+ }
+ ]
+ },
+ "16011":{
+ "inLabel":16011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16011,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.3.4"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.2.4"
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-rt4-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-rt4-1"
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17050,
+ "installed":true,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17051,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "16060":{
+ "inLabel":16060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.3.4"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.2.4"
+ }
+ ]
+ },
+ "16061":{
+ "inLabel":16061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-rt4-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-rt4-1"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt2/step9/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt2/step9/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..0879b84d23
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/step9/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step1/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt2/zebra.conf b/tests/topotests/isis-sr-topo1/rt2/zebra.conf
new file mode 100644
index 0000000000..dcb0686dc2
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt2/zebra.conf
@@ -0,0 +1,25 @@
+log file zebra.log
+!
+hostname rt2
+!
+debug zebra kernel
+debug zebra packet
+debug zebra mpls
+!
+interface lo
+ ip address 2.2.2.2/32
+ ipv6 address 2001:db8:1000::2/128
+!
+interface eth-sw1
+ ip address 10.0.1.2/24
+!
+interface eth-rt4-1
+ ip address 10.0.2.2/24
+!
+interface eth-rt4-2
+ ip address 10.0.3.2/24
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-sr-topo1/rt3/isisd.conf b/tests/topotests/isis-sr-topo1/rt3/isisd.conf
new file mode 100644
index 0000000000..ceb982ca32
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/isisd.conf
@@ -0,0 +1,41 @@
+hostname rt3
+log file isisd.log
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+debug isis sr-events
+debug isis lsp-gen
+!
+interface lo
+ ip router isis 1
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-sw1
+ ip router isis 1
+ ipv6 router isis 1
+ isis hello-multiplier 3
+!
+interface eth-rt5-1
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+!
+interface eth-rt5-2
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+!
+router isis 1
+ net 49.0000.0000.0000.0003.00
+ is-type level-1
+ topology ipv6-unicast
+ segment-routing on
+ segment-routing global-block 17000 24999
+ segment-routing node-msd 8
+ segment-routing prefix 3.3.3.3/32 index 30 no-php-flag
+ segment-routing prefix 2001:db8:1000::3/128 index 31 no-php-flag
+!
diff --git a/tests/topotests/isis-sr-topo1/rt3/step1/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt3/step1/show_ip_route.ref
new file mode 100644
index 0000000000..8d4fbec4b5
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step1/show_ip_route.ref
@@ -0,0 +1,347 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 3
+ ]
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+ "labels":[
+ 16050
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+ 16050
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ },
+ {
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1"
+ },
+ {
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2"
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt3/step1/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt3/step1/show_ipv6_route.ref
new file mode 100644
index 0000000000..4e4961eaf0
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step1/show_ipv6_route.ref
@@ -0,0 +1,148 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 3
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+ 16051
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+ "labels":[
+ 16051
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt3/step1/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt3/step1/show_mpls_table.ref
new file mode 100644
index 0000000000..b7bdc3e4af
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step1/show_mpls_table.ref
@@ -0,0 +1,192 @@
+{
+ "17010":{
+ "inLabel":17010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+ "nexthop":"10.0.1.1"
+ }
+ ]
+ },
+ "17011":{
+ "inLabel":17011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "17020":{
+ "inLabel":17020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "17021":{
+ "inLabel":17021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "17030":{
+ "inLabel":17030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "17031":{
+ "inLabel":17031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "17040":{
+ "inLabel":17040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.5.5"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.4.5"
+ }
+ ]
+ },
+ "17041":{
+ "inLabel":17041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-sw1"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-rt5-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-rt5-1"
+ }
+ ]
+ },
+ "17050":{
+ "inLabel":17050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16050,
+ "installed":true,
+ "nexthop":"10.0.5.5"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16050,
+ "installed":true,
+ "nexthop":"10.0.4.5"
+ }
+ ]
+ },
+ "17051":{
+ "inLabel":17051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16051,
+ "installed":true,
+ "interface":"eth-rt5-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16051,
+ "installed":true,
+ "interface":"eth-rt5-1"
+ }
+ ]
+ },
+ "17060":{
+ "inLabel":17060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.5.5"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.4.5"
+ }
+ ]
+ },
+ "17061":{
+ "inLabel":17061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-rt5-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-rt5-1"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt3/step1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt3/step1/show_yang_interface_isis_adjacencies.ref
new file mode 100644
index 0000000000..82069cec48
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step1/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1,74 @@
+{
+ "frr-interface:lib": {
+ "interface": [
+ {
+ "name": "eth-rt5-1",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0005",
+ "neighbor-extended-circuit-id": 0,
+ "hold-timer": 9,
+ "neighbor-priority": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "name": "eth-rt5-2",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0005",
+ "neighbor-extended-circuit-id": 0,
+ "hold-timer": 9,
+ "neighbor-priority": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "name": "eth-sw1",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0001",
+ "neighbor-extended-circuit-id": 2,
+ "hold-timer": 9,
+ "neighbor-priority": 64,
+ "state": "up"
+ },
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0002",
+ "neighbor-extended-circuit-id": 2,
+ "hold-timer": 9,
+ "neighbor-priority": 64,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt3/step10/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt3/step10/show_ip_route.ref
new file mode 100644
index 0000000000..9522b141b0
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step10/show_ip_route.ref
@@ -0,0 +1,327 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16010
+ ]
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+ "labels":[
+ 16050
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+ 16050
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ },
+ {
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1"
+ },
+ {
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2"
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt3/step10/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt3/step10/show_ipv6_route.ref
new file mode 100644
index 0000000000..fb630bc68f
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step10/show_ipv6_route.ref
@@ -0,0 +1,130 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16011
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+ 16051
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+ "labels":[
+ 16051
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt3/step10/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt3/step10/show_mpls_table.ref
new file mode 100644
index 0000000000..4aec3b6904
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step10/show_mpls_table.ref
@@ -0,0 +1,168 @@
+{
+ "17010":{
+ "inLabel":17010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16010,
+ "installed":true,
+ "nexthop":"10.0.1.1"
+ }
+ ]
+ },
+ "17011":{
+ "inLabel":17011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16011,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "17020":{
+ "inLabel":17020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "17021":{
+ "inLabel":17021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "17030":{
+ "inLabel":17030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "17031":{
+ "inLabel":17031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "17040":{
+ "inLabel":17040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "17041":{
+ "inLabel":17041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "17050":{
+ "inLabel":17050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16050,
+ "installed":true,
+ "nexthop":"10.0.5.5"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16050,
+ "installed":true,
+ "nexthop":"10.0.4.5"
+ }
+ ]
+ },
+ "17051":{
+ "inLabel":17051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16051,
+ "installed":true,
+ "interface":"eth-rt5-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16051,
+ "installed":true,
+ "interface":"eth-rt5-1"
+ }
+ ]
+ },
+ "17060":{
+ "inLabel":17060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.5.5"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.4.5"
+ }
+ ]
+ },
+ "17061":{
+ "inLabel":17061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-rt5-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-rt5-1"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt3/step10/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt3/step10/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..0879b84d23
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step10/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step1/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt3/step2/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt3/step2/show_ip_route.ref
new file mode 100644
index 0000000000..46ebeb8ab9
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step2/show_ip_route.ref
@@ -0,0 +1,327 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 3
+ ]
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+ "labels":[
+ 16050
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+ 16050
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ },
+ {
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1"
+ },
+ {
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2"
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt3/step2/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt3/step2/show_ipv6_route.ref
new file mode 100644
index 0000000000..b2c774d493
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step2/show_ipv6_route.ref
@@ -0,0 +1,130 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 3
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+ 16051
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+ "labels":[
+ 16051
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt3/step2/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt3/step2/show_mpls_table.ref
new file mode 100644
index 0000000000..a1e64afd67
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step2/show_mpls_table.ref
@@ -0,0 +1,168 @@
+{
+ "17010":{
+ "inLabel":17010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+ "nexthop":"10.0.1.1"
+ }
+ ]
+ },
+ "17011":{
+ "inLabel":17011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "17020":{
+ "inLabel":17020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "17021":{
+ "inLabel":17021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "17030":{
+ "inLabel":17030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "17031":{
+ "inLabel":17031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "17040":{
+ "inLabel":17040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "17041":{
+ "inLabel":17041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "17050":{
+ "inLabel":17050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16050,
+ "installed":true,
+ "nexthop":"10.0.5.5"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16050,
+ "installed":true,
+ "nexthop":"10.0.4.5"
+ }
+ ]
+ },
+ "17051":{
+ "inLabel":17051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16051,
+ "installed":true,
+ "interface":"eth-rt5-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16051,
+ "installed":true,
+ "interface":"eth-rt5-1"
+ }
+ ]
+ },
+ "17060":{
+ "inLabel":17060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.5.5"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.4.5"
+ }
+ ]
+ },
+ "17061":{
+ "inLabel":17061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-rt5-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-rt5-1"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt3/step2/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt3/step2/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..0879b84d23
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step2/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step1/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt3/step3/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt3/step3/show_ip_route.ref
new file mode 100644
index 0000000000..738aa17406
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step3/show_ip_route.ref
@@ -0,0 +1,280 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 3
+ ]
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+ "labels":[
+ 16050
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+ 16050
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ },
+ {
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1"
+ },
+ {
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2"
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt3/step3/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt3/step3/show_ipv6_route.ref
new file mode 100644
index 0000000000..b6423cd2b8
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step3/show_ipv6_route.ref
@@ -0,0 +1,99 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 3
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+ 16051
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+ "labels":[
+ 16051
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt3/step3/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt3/step3/show_mpls_table.ref
new file mode 100644
index 0000000000..1a2b8728e6
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step3/show_mpls_table.ref
@@ -0,0 +1,132 @@
+{
+ "17010":{
+ "inLabel":17010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+ "nexthop":"10.0.1.1"
+ }
+ ]
+ },
+ "17011":{
+ "inLabel":17011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "17020":{
+ "inLabel":17020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "17021":{
+ "inLabel":17021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "17030":{
+ "inLabel":17030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "17031":{
+ "inLabel":17031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "17040":{
+ "inLabel":17040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "17041":{
+ "inLabel":17041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "17050":{
+ "inLabel":17050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16050,
+ "installed":true,
+ "nexthop":"10.0.5.5"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16050,
+ "installed":true,
+ "nexthop":"10.0.4.5"
+ }
+ ]
+ },
+ "17051":{
+ "inLabel":17051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16051,
+ "installed":true,
+ "interface":"eth-rt5-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16051,
+ "installed":true,
+ "interface":"eth-rt5-1"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt3/step3/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt3/step3/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..0879b84d23
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step3/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step1/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt3/step4/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt3/step4/show_ip_route.ref
new file mode 100644
index 0000000000..46ebeb8ab9
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step4/show_ip_route.ref
@@ -0,0 +1,327 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 3
+ ]
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+ "labels":[
+ 16050
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+ 16050
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ },
+ {
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1"
+ },
+ {
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2"
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt3/step4/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt3/step4/show_ipv6_route.ref
new file mode 100644
index 0000000000..b2c774d493
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step4/show_ipv6_route.ref
@@ -0,0 +1,130 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 3
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+ 16051
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+ "labels":[
+ 16051
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt3/step4/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt3/step4/show_mpls_table.ref
new file mode 100644
index 0000000000..a1e64afd67
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step4/show_mpls_table.ref
@@ -0,0 +1,168 @@
+{
+ "17010":{
+ "inLabel":17010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+ "nexthop":"10.0.1.1"
+ }
+ ]
+ },
+ "17011":{
+ "inLabel":17011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "17020":{
+ "inLabel":17020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "17021":{
+ "inLabel":17021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "17030":{
+ "inLabel":17030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "17031":{
+ "inLabel":17031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "17040":{
+ "inLabel":17040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "17041":{
+ "inLabel":17041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "17050":{
+ "inLabel":17050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16050,
+ "installed":true,
+ "nexthop":"10.0.5.5"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16050,
+ "installed":true,
+ "nexthop":"10.0.4.5"
+ }
+ ]
+ },
+ "17051":{
+ "inLabel":17051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16051,
+ "installed":true,
+ "interface":"eth-rt5-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16051,
+ "installed":true,
+ "interface":"eth-rt5-1"
+ }
+ ]
+ },
+ "17060":{
+ "inLabel":17060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.5.5"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.4.5"
+ }
+ ]
+ },
+ "17061":{
+ "inLabel":17061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-rt5-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-rt5-1"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt3/step4/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt3/step4/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..0879b84d23
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step4/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step1/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt3/step5/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt3/step5/show_ip_route.ref
new file mode 100644
index 0000000000..489b495bb1
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step5/show_ip_route.ref
@@ -0,0 +1,321 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 3
+ ]
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+ "labels":[
+ 16050
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+ 16050
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ },
+ {
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1"
+ },
+ {
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2"
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt3/step5/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt3/step5/show_ipv6_route.ref
new file mode 100644
index 0000000000..46ee7ba28e
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step5/show_ipv6_route.ref
@@ -0,0 +1,124 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 3
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+ 16051
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+ "labels":[
+ 16051
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt3/step5/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt3/step5/show_mpls_table.ref
new file mode 100644
index 0000000000..1a2b8728e6
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step5/show_mpls_table.ref
@@ -0,0 +1,132 @@
+{
+ "17010":{
+ "inLabel":17010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+ "nexthop":"10.0.1.1"
+ }
+ ]
+ },
+ "17011":{
+ "inLabel":17011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "17020":{
+ "inLabel":17020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "17021":{
+ "inLabel":17021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "17030":{
+ "inLabel":17030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "17031":{
+ "inLabel":17031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "17040":{
+ "inLabel":17040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "17041":{
+ "inLabel":17041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "17050":{
+ "inLabel":17050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16050,
+ "installed":true,
+ "nexthop":"10.0.5.5"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16050,
+ "installed":true,
+ "nexthop":"10.0.4.5"
+ }
+ ]
+ },
+ "17051":{
+ "inLabel":17051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16051,
+ "installed":true,
+ "interface":"eth-rt5-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16051,
+ "installed":true,
+ "interface":"eth-rt5-1"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt3/step5/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt3/step5/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..0879b84d23
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step5/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step1/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt3/step6/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt3/step6/show_ip_route.ref
new file mode 100644
index 0000000000..46ebeb8ab9
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step6/show_ip_route.ref
@@ -0,0 +1,327 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 3
+ ]
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+ "labels":[
+ 16050
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+ 16050
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ },
+ {
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1"
+ },
+ {
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2"
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt3/step6/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt3/step6/show_ipv6_route.ref
new file mode 100644
index 0000000000..b2c774d493
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step6/show_ipv6_route.ref
@@ -0,0 +1,130 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 3
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+ 16051
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+ "labels":[
+ 16051
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt3/step6/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt3/step6/show_mpls_table.ref
new file mode 100644
index 0000000000..a1e64afd67
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step6/show_mpls_table.ref
@@ -0,0 +1,168 @@
+{
+ "17010":{
+ "inLabel":17010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+ "nexthop":"10.0.1.1"
+ }
+ ]
+ },
+ "17011":{
+ "inLabel":17011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "17020":{
+ "inLabel":17020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "17021":{
+ "inLabel":17021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "17030":{
+ "inLabel":17030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "17031":{
+ "inLabel":17031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "17040":{
+ "inLabel":17040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "17041":{
+ "inLabel":17041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "17050":{
+ "inLabel":17050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16050,
+ "installed":true,
+ "nexthop":"10.0.5.5"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16050,
+ "installed":true,
+ "nexthop":"10.0.4.5"
+ }
+ ]
+ },
+ "17051":{
+ "inLabel":17051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16051,
+ "installed":true,
+ "interface":"eth-rt5-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16051,
+ "installed":true,
+ "interface":"eth-rt5-1"
+ }
+ ]
+ },
+ "17060":{
+ "inLabel":17060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.5.5"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.4.5"
+ }
+ ]
+ },
+ "17061":{
+ "inLabel":17061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-rt5-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-rt5-1"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt3/step6/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt3/step6/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..0879b84d23
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step6/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step1/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt3/step7/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt3/step7/show_ip_route.ref
new file mode 100644
index 0000000000..1e8c27c01f
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step7/show_ip_route.ref
@@ -0,0 +1,324 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+ "labels":[
+ 16050
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+ 16050
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ },
+ {
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1"
+ },
+ {
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2"
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt3/step7/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt3/step7/show_ipv6_route.ref
new file mode 100644
index 0000000000..d21700d407
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step7/show_ipv6_route.ref
@@ -0,0 +1,127 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+ 16051
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+ "labels":[
+ 16051
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt3/step7/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt3/step7/show_mpls_table.ref
new file mode 100644
index 0000000000..e97e0d017b
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step7/show_mpls_table.ref
@@ -0,0 +1,144 @@
+{
+ "17020":{
+ "inLabel":17020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "17021":{
+ "inLabel":17021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "17030":{
+ "inLabel":17030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "17031":{
+ "inLabel":17031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "17040":{
+ "inLabel":17040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "17041":{
+ "inLabel":17041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "17050":{
+ "inLabel":17050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16050,
+ "installed":true,
+ "nexthop":"10.0.5.5"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16050,
+ "installed":true,
+ "nexthop":"10.0.4.5"
+ }
+ ]
+ },
+ "17051":{
+ "inLabel":17051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16051,
+ "installed":true,
+ "interface":"eth-rt5-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16051,
+ "installed":true,
+ "interface":"eth-rt5-1"
+ }
+ ]
+ },
+ "17060":{
+ "inLabel":17060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.5.5"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.4.5"
+ }
+ ]
+ },
+ "17061":{
+ "inLabel":17061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-rt5-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-rt5-1"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt3/step7/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt3/step7/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..0879b84d23
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step7/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step1/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt3/step8/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt3/step8/show_ip_route.ref
new file mode 100644
index 0000000000..46ebeb8ab9
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step8/show_ip_route.ref
@@ -0,0 +1,327 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 3
+ ]
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+ "labels":[
+ 16050
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+ 16050
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ },
+ {
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1"
+ },
+ {
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2"
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt3/step8/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt3/step8/show_ipv6_route.ref
new file mode 100644
index 0000000000..b2c774d493
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step8/show_ipv6_route.ref
@@ -0,0 +1,130 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 3
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+ 16051
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+ "labels":[
+ 16051
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt3/step8/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt3/step8/show_mpls_table.ref
new file mode 100644
index 0000000000..a1e64afd67
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step8/show_mpls_table.ref
@@ -0,0 +1,168 @@
+{
+ "17010":{
+ "inLabel":17010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+ "nexthop":"10.0.1.1"
+ }
+ ]
+ },
+ "17011":{
+ "inLabel":17011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "17020":{
+ "inLabel":17020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "17021":{
+ "inLabel":17021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "17030":{
+ "inLabel":17030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "17031":{
+ "inLabel":17031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "17040":{
+ "inLabel":17040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "17041":{
+ "inLabel":17041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "17050":{
+ "inLabel":17050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16050,
+ "installed":true,
+ "nexthop":"10.0.5.5"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16050,
+ "installed":true,
+ "nexthop":"10.0.4.5"
+ }
+ ]
+ },
+ "17051":{
+ "inLabel":17051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16051,
+ "installed":true,
+ "interface":"eth-rt5-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16051,
+ "installed":true,
+ "interface":"eth-rt5-1"
+ }
+ ]
+ },
+ "17060":{
+ "inLabel":17060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.5.5"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.4.5"
+ }
+ ]
+ },
+ "17061":{
+ "inLabel":17061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-rt5-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-rt5-1"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt3/step8/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt3/step8/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..0879b84d23
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step8/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step1/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt3/step9/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt3/step9/show_ip_route.ref
new file mode 100644
index 0000000000..9522b141b0
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step9/show_ip_route.ref
@@ -0,0 +1,327 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16010
+ ]
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+ "labels":[
+ 16050
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+ 16050
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+ 16060
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.1.1",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ },
+ {
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1"
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1"
+ },
+ {
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2"
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-sw1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5-2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt3/step9/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt3/step9/show_ipv6_route.ref
new file mode 100644
index 0000000000..fb630bc68f
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step9/show_ipv6_route.ref
@@ -0,0 +1,130 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16011
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-sw1",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+ 16051
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+ "labels":[
+ 16051
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+ "labels":[
+ 16061
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt3/step9/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt3/step9/show_mpls_table.ref
new file mode 100644
index 0000000000..4aec3b6904
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step9/show_mpls_table.ref
@@ -0,0 +1,168 @@
+{
+ "17010":{
+ "inLabel":17010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16010,
+ "installed":true,
+ "nexthop":"10.0.1.1"
+ }
+ ]
+ },
+ "17011":{
+ "inLabel":17011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16011,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "17020":{
+ "inLabel":17020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "17021":{
+ "inLabel":17021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "17030":{
+ "inLabel":17030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "17031":{
+ "inLabel":17031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "17040":{
+ "inLabel":17040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+ },
+ "17041":{
+ "inLabel":17041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
+ },
+ "17050":{
+ "inLabel":17050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16050,
+ "installed":true,
+ "nexthop":"10.0.5.5"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16050,
+ "installed":true,
+ "nexthop":"10.0.4.5"
+ }
+ ]
+ },
+ "17051":{
+ "inLabel":17051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16051,
+ "installed":true,
+ "interface":"eth-rt5-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16051,
+ "installed":true,
+ "interface":"eth-rt5-1"
+ }
+ ]
+ },
+ "17060":{
+ "inLabel":17060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.5.5"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+ "nexthop":"10.0.4.5"
+ }
+ ]
+ },
+ "17061":{
+ "inLabel":17061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-rt5-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+ "installed":true,
+ "interface":"eth-rt5-1"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt3/step9/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt3/step9/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..0879b84d23
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/step9/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step1/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt3/zebra.conf b/tests/topotests/isis-sr-topo1/rt3/zebra.conf
new file mode 100644
index 0000000000..3254529386
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt3/zebra.conf
@@ -0,0 +1,25 @@
+log file zebra.log
+!
+hostname rt3
+!
+debug zebra kernel
+debug zebra packet
+debug zebra mpls
+!
+interface lo
+ ip address 3.3.3.3/32
+ ipv6 address 2001:db8:1000::3/128
+!
+interface eth-sw1
+ ip address 10.0.1.3/24
+!
+interface eth-rt5-1
+ ip address 10.0.4.3/24
+!
+interface eth-rt5-2
+ ip address 10.0.5.3/24
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-sr-topo1/rt4/isisd.conf b/tests/topotests/isis-sr-topo1/rt4/isisd.conf
new file mode 100644
index 0000000000..07a7867cbb
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/isisd.conf
@@ -0,0 +1,48 @@
+hostname rt4
+log file isisd.log
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+debug isis sr-events
+debug isis lsp-gen
+!
+interface lo
+ ip router isis 1
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-rt2-1
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+!
+interface eth-rt2-2
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+!
+interface eth-rt5
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+!
+interface eth-rt6
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+!
+router isis 1
+ net 49.0000.0000.0000.0004.00
+ is-type level-1
+ topology ipv6-unicast
+ segment-routing on
+ segment-routing global-block 16000 23999
+ segment-routing node-msd 8
+ segment-routing prefix 4.4.4.4/32 index 40 no-php-flag
+ segment-routing prefix 2001:db8:1000::4/128 index 41 no-php-flag
+!
diff --git a/tests/topotests/isis-sr-topo1/rt4/step1/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt4/step1/show_ip_route.ref
new file mode 100644
index 0000000000..f06182b088
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step1/show_ip_route.ref
@@ -0,0 +1,323 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16010
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16010
+ ]
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16030
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16030
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.6.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16030
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.6.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16050
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 0
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1"
+ },
+ {
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2"
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.6.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.6.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.6.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5"
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.6.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt4/step1/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt4/step1/show_ipv6_route.ref
new file mode 100644
index 0000000000..f5772f2726
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step1/show_ipv6_route.ref
@@ -0,0 +1,148 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16011
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16011
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16031
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16031
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16051
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 2
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt4/step1/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt4/step1/show_mpls_table.ref
new file mode 100644
index 0000000000..b7fb69dcde
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step1/show_mpls_table.ref
@@ -0,0 +1,192 @@
+{
+ "16010":{
+ "inLabel":16010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16010,
+ "installed":true,
+ "nexthop":"10.0.3.2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16010,
+ "installed":true,
+ "nexthop":"10.0.2.2"
+ }
+ ]
+ },
+ "16011":{
+ "inLabel":16011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16011,
+ "installed":true,
+ "interface":"eth-rt2-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16011,
+ "installed":true,
+ "interface":"eth-rt2-1"
+ }
+ ]
+ },
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.3.2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.2.2"
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-rt2-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-rt2-1"
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16030,
+ "installed":true,
+ "nexthop":"10.0.3.2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16030,
+ "installed":true,
+ "nexthop":"10.0.2.2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16030,
+ "installed":true,
+ "nexthop":"10.0.6.5"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16031,
+ "installed":true,
+ "interface":"eth-rt2-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16031,
+ "installed":true,
+ "interface":"eth-rt2-1"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16031,
+ "installed":true,
+ "interface":"eth-rt5"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16050,
+ "installed":true,
+ "nexthop":"10.0.6.5"
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16051,
+ "installed":true,
+ "interface":"eth-rt5"
+ }
+ ]
+ },
+ "16060":{
+ "inLabel":16060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":0,
+ "installed":true,
+ "nexthop":"10.0.7.6"
+ }
+ ]
+ },
+ "16061":{
+ "inLabel":16061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":2,
+ "installed":true,
+ "interface":"eth-rt6"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt4/step1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt4/step1/show_yang_interface_isis_adjacencies.ref
new file mode 100644
index 0000000000..9d7a19e868
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step1/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1,86 @@
+{
+ "frr-interface:lib": {
+ "interface": [
+ {
+ "name": "eth-rt2-1",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0002",
+ "neighbor-extended-circuit-id": 0,
+ "hold-timer": 9,
+ "neighbor-priority": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "name": "eth-rt2-2",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0002",
+ "neighbor-extended-circuit-id": 0,
+ "hold-timer": 9,
+ "neighbor-priority": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "name": "eth-rt5",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0005",
+ "neighbor-extended-circuit-id": 0,
+ "hold-timer": 9,
+ "neighbor-priority": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "name": "eth-rt6",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0006",
+ "neighbor-extended-circuit-id": 0,
+ "hold-timer": 9,
+ "neighbor-priority": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt4/step10/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt4/step10/show_ip_route.ref
new file mode 100644
index 0000000000..d7d42120a0
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step10/show_ip_route.ref
@@ -0,0 +1,277 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16010
+ ]
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16030
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 18050
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 3
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2"
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":30,
+ "nexthops":[
+ {
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt4/step10/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt4/step10/show_ipv6_route.ref
new file mode 100644
index 0000000000..235c1facc6
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step10/show_ipv6_route.ref
@@ -0,0 +1,139 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16011
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16011
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16031
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 18051
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 3
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt4/step10/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt4/step10/show_mpls_table.ref
new file mode 100644
index 0000000000..86ceaf4883
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step10/show_mpls_table.ref
@@ -0,0 +1,162 @@
+{
+ "16010":{
+ "inLabel":16010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16010,
+ "installed":true,
+ "nexthop":"10.0.3.2"
+ }
+ ]
+ },
+ "16011":{
+ "inLabel":16011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16011,
+ "installed":true,
+ "interface":"eth-rt2-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16011,
+ "installed":true,
+ "interface":"eth-rt2-1"
+ }
+ ]
+ },
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.3.2"
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-rt2-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-rt2-1"
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16030,
+ "installed":true,
+ "nexthop":"10.0.3.2"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16031,
+ "installed":true,
+ "interface":"eth-rt2-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16031,
+ "installed":true,
+ "interface":"eth-rt2-1"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":18050,
+ "installed":true,
+ "nexthop":"10.0.7.6"
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":18051,
+ "installed":true,
+ "interface":"eth-rt6"
+ }
+ ]
+ },
+ "16060":{
+ "inLabel":16060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+ "nexthop":"10.0.7.6"
+ }
+ ]
+ },
+ "16061":{
+ "inLabel":16061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+ "interface":"eth-rt6"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt4/step10/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt4/step10/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..761cb2fd2f
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step10/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step2/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt4/step2/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt4/step2/show_ip_route.ref
new file mode 100644
index 0000000000..4789f7268f
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step2/show_ip_route.ref
@@ -0,0 +1,335 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16010
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16010
+ ]
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16030
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16030
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 16050
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 0
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1"
+ },
+ {
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2"
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":30,
+ "nexthops":[
+ {
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt4/step2/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt4/step2/show_ipv6_route.ref
new file mode 100644
index 0000000000..871b303cab
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step2/show_ipv6_route.ref
@@ -0,0 +1,139 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16011
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16011
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16031
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 16051
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 2
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt4/step2/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt4/step2/show_mpls_table.ref
new file mode 100644
index 0000000000..ff83c374f0
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step2/show_mpls_table.ref
@@ -0,0 +1,180 @@
+{
+ "16010":{
+ "inLabel":16010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16010,
+ "installed":true,
+ "nexthop":"10.0.3.2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16010,
+ "installed":true,
+ "nexthop":"10.0.2.2"
+ }
+ ]
+ },
+ "16011":{
+ "inLabel":16011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16011,
+ "installed":true,
+ "interface":"eth-rt2-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16011,
+ "installed":true,
+ "interface":"eth-rt2-1"
+ }
+ ]
+ },
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.3.2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.2.2"
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-rt2-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-rt2-1"
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16030,
+ "installed":true,
+ "nexthop":"10.0.3.2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16030,
+ "installed":true,
+ "nexthop":"10.0.2.2"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16031,
+ "installed":true,
+ "interface":"eth-rt2-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16031,
+ "installed":true,
+ "interface":"eth-rt2-1"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16050,
+ "installed":true,
+ "nexthop":"10.0.7.6"
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16051,
+ "installed":true,
+ "interface":"eth-rt6"
+ }
+ ]
+ },
+ "16060":{
+ "inLabel":16060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":0,
+ "installed":true,
+ "nexthop":"10.0.7.6"
+ }
+ ]
+ },
+ "16061":{
+ "inLabel":16061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":2,
+ "installed":true,
+ "interface":"eth-rt6"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt4/step2/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt4/step2/show_yang_interface_isis_adjacencies.ref
new file mode 100644
index 0000000000..5fb8a361ac
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step2/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1,66 @@
+{
+ "frr-interface:lib": {
+ "interface": [
+ {
+ "name": "eth-rt2-1",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0002",
+ "neighbor-extended-circuit-id": 0,
+ "hold-timer": 9,
+ "neighbor-priority": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "name": "eth-rt2-2",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0002",
+ "neighbor-extended-circuit-id": 0,
+ "hold-timer": 9,
+ "neighbor-priority": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "name": "eth-rt6",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0006",
+ "neighbor-extended-circuit-id": 0,
+ "hold-timer": 9,
+ "neighbor-priority": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt4/step3/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt4/step3/show_ip_route.ref
new file mode 100644
index 0000000000..d86562deb9
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step3/show_ip_route.ref
@@ -0,0 +1,306 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16010
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16010
+ ]
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16030
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16030
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16050
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16050
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1"
+ },
+ {
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2"
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":40,
+ "nexthops":[
+ {
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt4/step3/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt4/step3/show_ipv6_route.ref
new file mode 100644
index 0000000000..c09f584641
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step3/show_ipv6_route.ref
@@ -0,0 +1,126 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16011
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16011
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16031
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16051
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16051
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt4/step3/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt4/step3/show_mpls_table.ref
new file mode 100644
index 0000000000..85c6c055c9
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step3/show_mpls_table.ref
@@ -0,0 +1,168 @@
+{
+ "16010":{
+ "inLabel":16010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16010,
+ "installed":true,
+ "nexthop":"10.0.3.2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16010,
+ "installed":true,
+ "nexthop":"10.0.2.2"
+ }
+ ]
+ },
+ "16011":{
+ "inLabel":16011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16011,
+ "installed":true,
+ "interface":"eth-rt2-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16011,
+ "installed":true,
+ "interface":"eth-rt2-1"
+ }
+ ]
+ },
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.3.2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.2.2"
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-rt2-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-rt2-1"
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16030,
+ "installed":true,
+ "nexthop":"10.0.3.2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16030,
+ "installed":true,
+ "nexthop":"10.0.2.2"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16031,
+ "installed":true,
+ "interface":"eth-rt2-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16031,
+ "installed":true,
+ "interface":"eth-rt2-1"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16050,
+ "installed":true,
+ "nexthop":"10.0.3.2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16050,
+ "installed":true,
+ "nexthop":"10.0.2.2"
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16051,
+ "installed":true,
+ "interface":"eth-rt2-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16051,
+ "installed":true,
+ "interface":"eth-rt2-1"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt4/step3/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt4/step3/show_yang_interface_isis_adjacencies.ref
new file mode 100644
index 0000000000..2a56f54e16
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step3/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1,46 @@
+{
+ "frr-interface:lib": {
+ "interface": [
+ {
+ "name": "eth-rt2-1",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0002",
+ "neighbor-extended-circuit-id": 0,
+ "hold-timer": 9,
+ "neighbor-priority": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "name": "eth-rt2-2",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0002",
+ "neighbor-extended-circuit-id": 0,
+ "hold-timer": 9,
+ "neighbor-priority": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt4/step4/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt4/step4/show_ip_route.ref
new file mode 100644
index 0000000000..3c7dfda0a3
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step4/show_ip_route.ref
@@ -0,0 +1,335 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16010
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16010
+ ]
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16030
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16030
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 18050
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 0
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1"
+ },
+ {
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2"
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":30,
+ "nexthops":[
+ {
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt4/step4/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt4/step4/show_ipv6_route.ref
new file mode 100644
index 0000000000..38b51822dd
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step4/show_ipv6_route.ref
@@ -0,0 +1,139 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16011
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16011
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16031
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 18051
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 2
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt4/step4/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt4/step4/show_mpls_table.ref
new file mode 100644
index 0000000000..4e5638f34f
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step4/show_mpls_table.ref
@@ -0,0 +1,180 @@
+{
+ "16010":{
+ "inLabel":16010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16010,
+ "installed":true,
+ "nexthop":"10.0.3.2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16010,
+ "installed":true,
+ "nexthop":"10.0.2.2"
+ }
+ ]
+ },
+ "16011":{
+ "inLabel":16011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16011,
+ "installed":true,
+ "interface":"eth-rt2-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16011,
+ "installed":true,
+ "interface":"eth-rt2-1"
+ }
+ ]
+ },
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.3.2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.2.2"
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-rt2-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-rt2-1"
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16030,
+ "installed":true,
+ "nexthop":"10.0.3.2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16030,
+ "installed":true,
+ "nexthop":"10.0.2.2"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16031,
+ "installed":true,
+ "interface":"eth-rt2-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16031,
+ "installed":true,
+ "interface":"eth-rt2-1"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":18050,
+ "installed":true,
+ "nexthop":"10.0.7.6"
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":18051,
+ "installed":true,
+ "interface":"eth-rt6"
+ }
+ ]
+ },
+ "16060":{
+ "inLabel":16060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":0,
+ "installed":true,
+ "nexthop":"10.0.7.6"
+ }
+ ]
+ },
+ "16061":{
+ "inLabel":16061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":2,
+ "installed":true,
+ "interface":"eth-rt6"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt4/step4/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt4/step4/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..761cb2fd2f
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step4/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step2/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt4/step5/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt4/step5/show_ip_route.ref
new file mode 100644
index 0000000000..90f69c06b8
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step5/show_ip_route.ref
@@ -0,0 +1,329 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16010
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16010
+ ]
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16030
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16030
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1"
+ },
+ {
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2"
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":30,
+ "nexthops":[
+ {
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt4/step5/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt4/step5/show_ipv6_route.ref
new file mode 100644
index 0000000000..04056ed873
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step5/show_ipv6_route.ref
@@ -0,0 +1,133 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16011
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16011
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16031
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt4/step5/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt4/step5/show_mpls_table.ref
new file mode 100644
index 0000000000..4df722be4f
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step5/show_mpls_table.ref
@@ -0,0 +1,132 @@
+{
+ "16010":{
+ "inLabel":16010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16010,
+ "installed":true,
+ "nexthop":"10.0.3.2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16010,
+ "installed":true,
+ "nexthop":"10.0.2.2"
+ }
+ ]
+ },
+ "16011":{
+ "inLabel":16011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16011,
+ "installed":true,
+ "interface":"eth-rt2-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16011,
+ "installed":true,
+ "interface":"eth-rt2-1"
+ }
+ ]
+ },
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.3.2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.2.2"
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-rt2-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-rt2-1"
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16030,
+ "installed":true,
+ "nexthop":"10.0.3.2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16030,
+ "installed":true,
+ "nexthop":"10.0.2.2"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16031,
+ "installed":true,
+ "interface":"eth-rt2-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16031,
+ "installed":true,
+ "interface":"eth-rt2-1"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt4/step5/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt4/step5/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..761cb2fd2f
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step5/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step2/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt4/step6/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt4/step6/show_ip_route.ref
new file mode 100644
index 0000000000..3c7dfda0a3
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step6/show_ip_route.ref
@@ -0,0 +1,335 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16010
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16010
+ ]
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16030
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16030
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 18050
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 0
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1"
+ },
+ {
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2"
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":30,
+ "nexthops":[
+ {
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt4/step6/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt4/step6/show_ipv6_route.ref
new file mode 100644
index 0000000000..38b51822dd
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step6/show_ipv6_route.ref
@@ -0,0 +1,139 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16011
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16011
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16031
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 18051
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 2
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt4/step6/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt4/step6/show_mpls_table.ref
new file mode 100644
index 0000000000..4e5638f34f
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step6/show_mpls_table.ref
@@ -0,0 +1,180 @@
+{
+ "16010":{
+ "inLabel":16010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16010,
+ "installed":true,
+ "nexthop":"10.0.3.2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16010,
+ "installed":true,
+ "nexthop":"10.0.2.2"
+ }
+ ]
+ },
+ "16011":{
+ "inLabel":16011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16011,
+ "installed":true,
+ "interface":"eth-rt2-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16011,
+ "installed":true,
+ "interface":"eth-rt2-1"
+ }
+ ]
+ },
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.3.2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.2.2"
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-rt2-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-rt2-1"
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16030,
+ "installed":true,
+ "nexthop":"10.0.3.2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16030,
+ "installed":true,
+ "nexthop":"10.0.2.2"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16031,
+ "installed":true,
+ "interface":"eth-rt2-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16031,
+ "installed":true,
+ "interface":"eth-rt2-1"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":18050,
+ "installed":true,
+ "nexthop":"10.0.7.6"
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":18051,
+ "installed":true,
+ "interface":"eth-rt6"
+ }
+ ]
+ },
+ "16060":{
+ "inLabel":16060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":0,
+ "installed":true,
+ "nexthop":"10.0.7.6"
+ }
+ ]
+ },
+ "16061":{
+ "inLabel":16061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":2,
+ "installed":true,
+ "interface":"eth-rt6"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt4/step6/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt4/step6/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..761cb2fd2f
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step6/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step2/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt4/step7/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt4/step7/show_ip_route.ref
new file mode 100644
index 0000000000..a3ac4ac109
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step7/show_ip_route.ref
@@ -0,0 +1,329 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16030
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16030
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 18050
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 0
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1"
+ },
+ {
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2"
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":30,
+ "nexthops":[
+ {
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt4/step7/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt4/step7/show_ipv6_route.ref
new file mode 100644
index 0000000000..c59abbd2f5
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step7/show_ipv6_route.ref
@@ -0,0 +1,133 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16031
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 18051
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 2
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt4/step7/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt4/step7/show_mpls_table.ref
new file mode 100644
index 0000000000..512c057b31
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step7/show_mpls_table.ref
@@ -0,0 +1,144 @@
+{
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.3.2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.2.2"
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-rt2-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-rt2-1"
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16030,
+ "installed":true,
+ "nexthop":"10.0.3.2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16030,
+ "installed":true,
+ "nexthop":"10.0.2.2"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16031,
+ "installed":true,
+ "interface":"eth-rt2-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16031,
+ "installed":true,
+ "interface":"eth-rt2-1"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":18050,
+ "installed":true,
+ "nexthop":"10.0.7.6"
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":18051,
+ "installed":true,
+ "interface":"eth-rt6"
+ }
+ ]
+ },
+ "16060":{
+ "inLabel":16060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":0,
+ "installed":true,
+ "nexthop":"10.0.7.6"
+ }
+ ]
+ },
+ "16061":{
+ "inLabel":16061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":2,
+ "installed":true,
+ "interface":"eth-rt6"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt4/step7/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt4/step7/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..761cb2fd2f
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step7/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step2/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt4/step8/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt4/step8/show_ip_route.ref
new file mode 100644
index 0000000000..3c7dfda0a3
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step8/show_ip_route.ref
@@ -0,0 +1,335 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16010
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16010
+ ]
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16030
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16030
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 18050
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 0
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1"
+ },
+ {
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2"
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":30,
+ "nexthops":[
+ {
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt4/step8/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt4/step8/show_ipv6_route.ref
new file mode 100644
index 0000000000..38b51822dd
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step8/show_ipv6_route.ref
@@ -0,0 +1,139 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16011
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16011
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16031
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 18051
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 2
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt4/step8/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt4/step8/show_mpls_table.ref
new file mode 100644
index 0000000000..4e5638f34f
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step8/show_mpls_table.ref
@@ -0,0 +1,180 @@
+{
+ "16010":{
+ "inLabel":16010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16010,
+ "installed":true,
+ "nexthop":"10.0.3.2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16010,
+ "installed":true,
+ "nexthop":"10.0.2.2"
+ }
+ ]
+ },
+ "16011":{
+ "inLabel":16011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16011,
+ "installed":true,
+ "interface":"eth-rt2-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16011,
+ "installed":true,
+ "interface":"eth-rt2-1"
+ }
+ ]
+ },
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.3.2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.2.2"
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-rt2-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-rt2-1"
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16030,
+ "installed":true,
+ "nexthop":"10.0.3.2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16030,
+ "installed":true,
+ "nexthop":"10.0.2.2"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16031,
+ "installed":true,
+ "interface":"eth-rt2-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16031,
+ "installed":true,
+ "interface":"eth-rt2-1"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":18050,
+ "installed":true,
+ "nexthop":"10.0.7.6"
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":18051,
+ "installed":true,
+ "interface":"eth-rt6"
+ }
+ ]
+ },
+ "16060":{
+ "inLabel":16060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":0,
+ "installed":true,
+ "nexthop":"10.0.7.6"
+ }
+ ]
+ },
+ "16061":{
+ "inLabel":16061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":2,
+ "installed":true,
+ "interface":"eth-rt6"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt4/step8/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt4/step8/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..761cb2fd2f
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step8/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step2/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt4/step9/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt4/step9/show_ip_route.ref
new file mode 100644
index 0000000000..73598e4605
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step9/show_ip_route.ref
@@ -0,0 +1,335 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16010
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16010
+ ]
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16030
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16030
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 18050
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 3
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1"
+ },
+ {
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2"
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.3.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":30,
+ "nexthops":[
+ {
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt4/step9/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt4/step9/show_ipv6_route.ref
new file mode 100644
index 0000000000..235c1facc6
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step9/show_ipv6_route.ref
@@ -0,0 +1,139 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16011
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16011
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-2",
+ "active":true,
+ "labels":[
+ 16031
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt2-1",
+ "active":true,
+ "labels":[
+ 16031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 18051
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 3
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt4/step9/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt4/step9/show_mpls_table.ref
new file mode 100644
index 0000000000..5cdd99e425
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step9/show_mpls_table.ref
@@ -0,0 +1,180 @@
+{
+ "16010":{
+ "inLabel":16010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16010,
+ "installed":true,
+ "nexthop":"10.0.3.2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16010,
+ "installed":true,
+ "nexthop":"10.0.2.2"
+ }
+ ]
+ },
+ "16011":{
+ "inLabel":16011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16011,
+ "installed":true,
+ "interface":"eth-rt2-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16011,
+ "installed":true,
+ "interface":"eth-rt2-1"
+ }
+ ]
+ },
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.3.2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.2.2"
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-rt2-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-rt2-1"
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16030,
+ "installed":true,
+ "nexthop":"10.0.3.2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16030,
+ "installed":true,
+ "nexthop":"10.0.2.2"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16031,
+ "installed":true,
+ "interface":"eth-rt2-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16031,
+ "installed":true,
+ "interface":"eth-rt2-1"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":18050,
+ "installed":true,
+ "nexthop":"10.0.7.6"
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":18051,
+ "installed":true,
+ "interface":"eth-rt6"
+ }
+ ]
+ },
+ "16060":{
+ "inLabel":16060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+ "nexthop":"10.0.7.6"
+ }
+ ]
+ },
+ "16061":{
+ "inLabel":16061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+ "interface":"eth-rt6"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt4/step9/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt4/step9/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..761cb2fd2f
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/step9/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step2/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt4/zebra.conf b/tests/topotests/isis-sr-topo1/rt4/zebra.conf
new file mode 100644
index 0000000000..4945897e9d
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt4/zebra.conf
@@ -0,0 +1,28 @@
+log file zebra.log
+!
+hostname rt4
+!
+debug zebra kernel
+debug zebra packet
+debug zebra mpls
+!
+interface lo
+ ip address 4.4.4.4/32
+ ipv6 address 2001:db8:1000::4/128
+!
+interface eth-rt2-1
+ ip address 10.0.2.4/24
+!
+interface eth-rt2-2
+ ip address 10.0.3.4/24
+!
+interface eth-rt5
+ ip address 10.0.6.4/24
+!
+interface eth-rt6
+ ip address 10.0.7.4/24
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-sr-topo1/rt5/isisd.conf b/tests/topotests/isis-sr-topo1/rt5/isisd.conf
new file mode 100644
index 0000000000..b0fcdede07
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/isisd.conf
@@ -0,0 +1,48 @@
+hostname rt5
+log file isisd.log
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+debug isis sr-events
+debug isis lsp-gen
+!
+interface lo
+ ip router isis 1
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-rt3-1
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+!
+interface eth-rt3-2
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+!
+interface eth-rt4
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+!
+interface eth-rt6
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+!
+router isis 1
+ net 49.0000.0000.0000.0005.00
+ is-type level-1
+ topology ipv6-unicast
+ segment-routing on
+ segment-routing global-block 16000 23999
+ segment-routing node-msd 8
+ segment-routing prefix 5.5.5.5/32 index 50 no-php-flag
+ segment-routing prefix 2001:db8:1000::5/128 index 51 no-php-flag
+!
diff --git a/tests/topotests/isis-sr-topo1/rt5/step1/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt5/step1/show_ip_route.ref
new file mode 100644
index 0000000000..8eaf40f236
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step1/show_ip_route.ref
@@ -0,0 +1,323 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17010
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17010
+ ]
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17020
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17020
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.6.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.6.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 0
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.6.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.6.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1"
+ },
+ {
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2"
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.6.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4"
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.6.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt5/step1/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt5/step1/show_ipv6_route.ref
new file mode 100644
index 0000000000..294567edc8
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step1/show_ipv6_route.ref
@@ -0,0 +1,148 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17011
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17011
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17021
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 2
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt5/step1/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt5/step1/show_mpls_table.ref
new file mode 100644
index 0000000000..9054c9c4af
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step1/show_mpls_table.ref
@@ -0,0 +1,192 @@
+{
+ "16010":{
+ "inLabel":16010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17010,
+ "installed":true,
+ "nexthop":"10.0.5.3"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17010,
+ "installed":true,
+ "nexthop":"10.0.4.3"
+ }
+ ]
+ },
+ "16011":{
+ "inLabel":16011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17011,
+ "installed":true,
+ "interface":"eth-rt3-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17011,
+ "installed":true,
+ "interface":"eth-rt3-1"
+ }
+ ]
+ },
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17020,
+ "installed":true,
+ "nexthop":"10.0.5.3"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17020,
+ "installed":true,
+ "nexthop":"10.0.4.3"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.6.4"
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17021,
+ "installed":true,
+ "interface":"eth-rt3-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17021,
+ "installed":true,
+ "interface":"eth-rt3-1"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-rt4"
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.5.3"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.4.3"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-rt3-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-rt3-1"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.6.4"
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-rt4"
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16060":{
+ "inLabel":16060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":0,
+ "installed":true,
+ "nexthop":"10.0.8.6"
+ }
+ ]
+ },
+ "16061":{
+ "inLabel":16061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":2,
+ "installed":true,
+ "interface":"eth-rt6"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt5/step1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt5/step1/show_yang_interface_isis_adjacencies.ref
new file mode 100644
index 0000000000..4a3e626123
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step1/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1,86 @@
+{
+ "frr-interface:lib": {
+ "interface": [
+ {
+ "name": "eth-rt3-1",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0003",
+ "neighbor-extended-circuit-id": 0,
+ "hold-timer": 9,
+ "neighbor-priority": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "name": "eth-rt3-2",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0003",
+ "neighbor-extended-circuit-id": 0,
+ "hold-timer": 9,
+ "neighbor-priority": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "name": "eth-rt4",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0004",
+ "neighbor-extended-circuit-id": 0,
+ "hold-timer": 9,
+ "neighbor-priority": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "name": "eth-rt6",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0006",
+ "neighbor-extended-circuit-id": 0,
+ "hold-timer": 9,
+ "neighbor-priority": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt5/step10/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt5/step10/show_ip_route.ref
new file mode 100644
index 0000000000..a5a0bacaad
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step10/show_ip_route.ref
@@ -0,0 +1,312 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17010
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17010
+ ]
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17020
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17020
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 18040
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 3
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1"
+ },
+ {
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2"
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt5/step10/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt5/step10/show_ipv6_route.ref
new file mode 100644
index 0000000000..c02d3cfaea
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step10/show_ipv6_route.ref
@@ -0,0 +1,139 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17011
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17011
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17021
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 18041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 3
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt5/step10/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt5/step10/show_mpls_table.ref
new file mode 100644
index 0000000000..e43ef6671d
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step10/show_mpls_table.ref
@@ -0,0 +1,180 @@
+{
+ "16010":{
+ "inLabel":16010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17010,
+ "installed":true,
+ "nexthop":"10.0.5.3"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17010,
+ "installed":true,
+ "nexthop":"10.0.4.3"
+ }
+ ]
+ },
+ "16011":{
+ "inLabel":16011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17011,
+ "installed":true,
+ "interface":"eth-rt3-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17011,
+ "installed":true,
+ "interface":"eth-rt3-1"
+ }
+ ]
+ },
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17020,
+ "installed":true,
+ "nexthop":"10.0.5.3"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17020,
+ "installed":true,
+ "nexthop":"10.0.4.3"
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17021,
+ "installed":true,
+ "interface":"eth-rt3-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17021,
+ "installed":true,
+ "interface":"eth-rt3-1"
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.5.3"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.4.3"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-rt3-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-rt3-1"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":18040,
+ "installed":true,
+ "nexthop":"10.0.8.6"
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":18041,
+ "installed":true,
+ "interface":"eth-rt6"
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16060":{
+ "inLabel":16060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+ "nexthop":"10.0.8.6"
+ }
+ ]
+ },
+ "16061":{
+ "inLabel":16061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+ "interface":"eth-rt6"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt5/step10/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt5/step10/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..7cdaabf53f
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step10/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step4/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt5/step2/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt5/step2/show_ip_route.ref
new file mode 100644
index 0000000000..101b811d3b
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step2/show_ip_route.ref
@@ -0,0 +1,319 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17010
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17010
+ ]
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17020
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17020
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 0
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1"
+ },
+ {
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2"
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt5/step2/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt5/step2/show_ipv6_route.ref
new file mode 100644
index 0000000000..fa426317ba
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step2/show_ipv6_route.ref
@@ -0,0 +1,139 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17011
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17011
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17021
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 2
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt5/step2/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt5/step2/show_mpls_table.ref
new file mode 100644
index 0000000000..660e319a50
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step2/show_mpls_table.ref
@@ -0,0 +1,180 @@
+{
+ "16010":{
+ "inLabel":16010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17010,
+ "installed":true,
+ "nexthop":"10.0.5.3"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17010,
+ "installed":true,
+ "nexthop":"10.0.4.3"
+ }
+ ]
+ },
+ "16011":{
+ "inLabel":16011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17011,
+ "installed":true,
+ "interface":"eth-rt3-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17011,
+ "installed":true,
+ "interface":"eth-rt3-1"
+ }
+ ]
+ },
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17020,
+ "installed":true,
+ "nexthop":"10.0.5.3"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17020,
+ "installed":true,
+ "nexthop":"10.0.4.3"
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17021,
+ "installed":true,
+ "interface":"eth-rt3-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17021,
+ "installed":true,
+ "interface":"eth-rt3-1"
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.5.3"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.4.3"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-rt3-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-rt3-1"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.8.6"
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-rt6"
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16060":{
+ "inLabel":16060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":0,
+ "installed":true,
+ "nexthop":"10.0.8.6"
+ }
+ ]
+ },
+ "16061":{
+ "inLabel":16061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":2,
+ "installed":true,
+ "interface":"eth-rt6"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt5/step2/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt5/step2/show_yang_interface_isis_adjacencies.ref
new file mode 100644
index 0000000000..ae26b5be99
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step2/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1,66 @@
+{
+ "frr-interface:lib": {
+ "interface": [
+ {
+ "name": "eth-rt3-1",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0003",
+ "neighbor-extended-circuit-id": 0,
+ "hold-timer": 9,
+ "neighbor-priority": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "name": "eth-rt3-2",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0003",
+ "neighbor-extended-circuit-id": 0,
+ "hold-timer": 9,
+ "neighbor-priority": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "name": "eth-rt6",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0006",
+ "neighbor-extended-circuit-id": 0,
+ "hold-timer": 9,
+ "neighbor-priority": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt5/step3/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt5/step3/show_ip_route.ref
new file mode 100644
index 0000000000..dff6c5f7eb
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step3/show_ip_route.ref
@@ -0,0 +1,284 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17010
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17010
+ ]
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17020
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17020
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17040
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17040
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1"
+ },
+ {
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2"
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt5/step3/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt5/step3/show_ipv6_route.ref
new file mode 100644
index 0000000000..a3e705f384
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step3/show_ipv6_route.ref
@@ -0,0 +1,126 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17011
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17011
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17021
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17041
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17041
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt5/step3/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt5/step3/show_mpls_table.ref
new file mode 100644
index 0000000000..9df3fc9ef6
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step3/show_mpls_table.ref
@@ -0,0 +1,168 @@
+{
+ "16010":{
+ "inLabel":16010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17010,
+ "installed":true,
+ "nexthop":"10.0.5.3"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17010,
+ "installed":true,
+ "nexthop":"10.0.4.3"
+ }
+ ]
+ },
+ "16011":{
+ "inLabel":16011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17011,
+ "installed":true,
+ "interface":"eth-rt3-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17011,
+ "installed":true,
+ "interface":"eth-rt3-1"
+ }
+ ]
+ },
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17020,
+ "installed":true,
+ "nexthop":"10.0.5.3"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17020,
+ "installed":true,
+ "nexthop":"10.0.4.3"
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17021,
+ "installed":true,
+ "interface":"eth-rt3-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17021,
+ "installed":true,
+ "interface":"eth-rt3-1"
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.5.3"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.4.3"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-rt3-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-rt3-1"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17040,
+ "installed":true,
+ "nexthop":"10.0.5.3"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17040,
+ "installed":true,
+ "nexthop":"10.0.4.3"
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17041,
+ "installed":true,
+ "interface":"eth-rt3-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17041,
+ "installed":true,
+ "interface":"eth-rt3-1"
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt5/step3/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt5/step3/show_yang_interface_isis_adjacencies.ref
new file mode 100644
index 0000000000..7e62a65ea1
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step3/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1,46 @@
+{
+ "frr-interface:lib": {
+ "interface": [
+ {
+ "name": "eth-rt3-1",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0003",
+ "neighbor-extended-circuit-id": 0,
+ "hold-timer": 9,
+ "neighbor-priority": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "name": "eth-rt3-2",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0003",
+ "neighbor-extended-circuit-id": 0,
+ "hold-timer": 9,
+ "neighbor-priority": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt5/step4/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt5/step4/show_ip_route.ref
new file mode 100644
index 0000000000..6b29ff2d44
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step4/show_ip_route.ref
@@ -0,0 +1,319 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17010
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17010
+ ]
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17020
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17020
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 18040
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 0
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1"
+ },
+ {
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2"
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt5/step4/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt5/step4/show_ipv6_route.ref
new file mode 100644
index 0000000000..e9f8fe227c
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step4/show_ipv6_route.ref
@@ -0,0 +1,139 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17011
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17011
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17021
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 18041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 2
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt5/step4/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt5/step4/show_mpls_table.ref
new file mode 100644
index 0000000000..4d13108d7d
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step4/show_mpls_table.ref
@@ -0,0 +1,180 @@
+{
+ "16010":{
+ "inLabel":16010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17010,
+ "installed":true,
+ "nexthop":"10.0.5.3"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17010,
+ "installed":true,
+ "nexthop":"10.0.4.3"
+ }
+ ]
+ },
+ "16011":{
+ "inLabel":16011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17011,
+ "installed":true,
+ "interface":"eth-rt3-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17011,
+ "installed":true,
+ "interface":"eth-rt3-1"
+ }
+ ]
+ },
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17020,
+ "installed":true,
+ "nexthop":"10.0.5.3"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17020,
+ "installed":true,
+ "nexthop":"10.0.4.3"
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17021,
+ "installed":true,
+ "interface":"eth-rt3-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17021,
+ "installed":true,
+ "interface":"eth-rt3-1"
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.5.3"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.4.3"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-rt3-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-rt3-1"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":18040,
+ "installed":true,
+ "nexthop":"10.0.8.6"
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":18041,
+ "installed":true,
+ "interface":"eth-rt6"
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16060":{
+ "inLabel":16060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":0,
+ "installed":true,
+ "nexthop":"10.0.8.6"
+ }
+ ]
+ },
+ "16061":{
+ "inLabel":16061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":2,
+ "installed":true,
+ "interface":"eth-rt6"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt5/step4/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt5/step4/show_yang_interface_isis_adjacencies.ref
new file mode 100644
index 0000000000..ae26b5be99
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step4/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1,66 @@
+{
+ "frr-interface:lib": {
+ "interface": [
+ {
+ "name": "eth-rt3-1",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0003",
+ "neighbor-extended-circuit-id": 0,
+ "hold-timer": 9,
+ "neighbor-priority": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "name": "eth-rt3-2",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0003",
+ "neighbor-extended-circuit-id": 0,
+ "hold-timer": 9,
+ "neighbor-priority": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "name": "eth-rt6",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0006",
+ "neighbor-extended-circuit-id": 0,
+ "hold-timer": 9,
+ "neighbor-priority": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt5/step5/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt5/step5/show_ip_route.ref
new file mode 100644
index 0000000000..cadb674ba3
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step5/show_ip_route.ref
@@ -0,0 +1,313 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17010
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17010
+ ]
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17020
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17020
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1"
+ },
+ {
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2"
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt5/step5/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt5/step5/show_ipv6_route.ref
new file mode 100644
index 0000000000..60c645092e
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step5/show_ipv6_route.ref
@@ -0,0 +1,133 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17011
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17011
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17021
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt5/step5/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt5/step5/show_mpls_table.ref
new file mode 100644
index 0000000000..c60383093f
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step5/show_mpls_table.ref
@@ -0,0 +1,132 @@
+{
+ "16010":{
+ "inLabel":16010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17010,
+ "installed":true,
+ "nexthop":"10.0.5.3"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17010,
+ "installed":true,
+ "nexthop":"10.0.4.3"
+ }
+ ]
+ },
+ "16011":{
+ "inLabel":16011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17011,
+ "installed":true,
+ "interface":"eth-rt3-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17011,
+ "installed":true,
+ "interface":"eth-rt3-1"
+ }
+ ]
+ },
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17020,
+ "installed":true,
+ "nexthop":"10.0.5.3"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17020,
+ "installed":true,
+ "nexthop":"10.0.4.3"
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17021,
+ "installed":true,
+ "interface":"eth-rt3-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17021,
+ "installed":true,
+ "interface":"eth-rt3-1"
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.5.3"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.4.3"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-rt3-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-rt3-1"
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt5/step5/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt5/step5/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..7cdaabf53f
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step5/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step4/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt5/step6/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt5/step6/show_ip_route.ref
new file mode 100644
index 0000000000..6b29ff2d44
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step6/show_ip_route.ref
@@ -0,0 +1,319 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17010
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17010
+ ]
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17020
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17020
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 18040
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 0
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1"
+ },
+ {
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2"
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt5/step6/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt5/step6/show_ipv6_route.ref
new file mode 100644
index 0000000000..e9f8fe227c
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step6/show_ipv6_route.ref
@@ -0,0 +1,139 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17011
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17011
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17021
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 18041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 2
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt5/step6/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt5/step6/show_mpls_table.ref
new file mode 100644
index 0000000000..4d13108d7d
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step6/show_mpls_table.ref
@@ -0,0 +1,180 @@
+{
+ "16010":{
+ "inLabel":16010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17010,
+ "installed":true,
+ "nexthop":"10.0.5.3"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17010,
+ "installed":true,
+ "nexthop":"10.0.4.3"
+ }
+ ]
+ },
+ "16011":{
+ "inLabel":16011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17011,
+ "installed":true,
+ "interface":"eth-rt3-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17011,
+ "installed":true,
+ "interface":"eth-rt3-1"
+ }
+ ]
+ },
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17020,
+ "installed":true,
+ "nexthop":"10.0.5.3"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17020,
+ "installed":true,
+ "nexthop":"10.0.4.3"
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17021,
+ "installed":true,
+ "interface":"eth-rt3-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17021,
+ "installed":true,
+ "interface":"eth-rt3-1"
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.5.3"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.4.3"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-rt3-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-rt3-1"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":18040,
+ "installed":true,
+ "nexthop":"10.0.8.6"
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":18041,
+ "installed":true,
+ "interface":"eth-rt6"
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16060":{
+ "inLabel":16060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":0,
+ "installed":true,
+ "nexthop":"10.0.8.6"
+ }
+ ]
+ },
+ "16061":{
+ "inLabel":16061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":2,
+ "installed":true,
+ "interface":"eth-rt6"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt5/step6/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt5/step6/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..7cdaabf53f
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step6/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step4/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt5/step7/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt5/step7/show_ip_route.ref
new file mode 100644
index 0000000000..72b89ccf69
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step7/show_ip_route.ref
@@ -0,0 +1,313 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17020
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17020
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 18040
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 0
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1"
+ },
+ {
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2"
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt5/step7/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt5/step7/show_ipv6_route.ref
new file mode 100644
index 0000000000..e05cc1e282
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step7/show_ipv6_route.ref
@@ -0,0 +1,133 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17021
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 18041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 2
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt5/step7/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt5/step7/show_mpls_table.ref
new file mode 100644
index 0000000000..2b1e67ea71
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step7/show_mpls_table.ref
@@ -0,0 +1,144 @@
+{
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17020,
+ "installed":true,
+ "nexthop":"10.0.5.3"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17020,
+ "installed":true,
+ "nexthop":"10.0.4.3"
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17021,
+ "installed":true,
+ "interface":"eth-rt3-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17021,
+ "installed":true,
+ "interface":"eth-rt3-1"
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.5.3"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.4.3"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-rt3-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-rt3-1"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":18040,
+ "installed":true,
+ "nexthop":"10.0.8.6"
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":18041,
+ "installed":true,
+ "interface":"eth-rt6"
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16060":{
+ "inLabel":16060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":0,
+ "installed":true,
+ "nexthop":"10.0.8.6"
+ }
+ ]
+ },
+ "16061":{
+ "inLabel":16061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":2,
+ "installed":true,
+ "interface":"eth-rt6"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt5/step7/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt5/step7/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..7cdaabf53f
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step7/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step4/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt5/step8/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt5/step8/show_ip_route.ref
new file mode 100644
index 0000000000..6b29ff2d44
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step8/show_ip_route.ref
@@ -0,0 +1,319 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17010
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17010
+ ]
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17020
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17020
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 18040
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 0
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1"
+ },
+ {
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2"
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt5/step8/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt5/step8/show_ipv6_route.ref
new file mode 100644
index 0000000000..e9f8fe227c
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step8/show_ipv6_route.ref
@@ -0,0 +1,139 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17011
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17011
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17021
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 18041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 2
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt5/step8/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt5/step8/show_mpls_table.ref
new file mode 100644
index 0000000000..4d13108d7d
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step8/show_mpls_table.ref
@@ -0,0 +1,180 @@
+{
+ "16010":{
+ "inLabel":16010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17010,
+ "installed":true,
+ "nexthop":"10.0.5.3"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17010,
+ "installed":true,
+ "nexthop":"10.0.4.3"
+ }
+ ]
+ },
+ "16011":{
+ "inLabel":16011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17011,
+ "installed":true,
+ "interface":"eth-rt3-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17011,
+ "installed":true,
+ "interface":"eth-rt3-1"
+ }
+ ]
+ },
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17020,
+ "installed":true,
+ "nexthop":"10.0.5.3"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17020,
+ "installed":true,
+ "nexthop":"10.0.4.3"
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17021,
+ "installed":true,
+ "interface":"eth-rt3-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17021,
+ "installed":true,
+ "interface":"eth-rt3-1"
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.5.3"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.4.3"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-rt3-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-rt3-1"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":18040,
+ "installed":true,
+ "nexthop":"10.0.8.6"
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":18041,
+ "installed":true,
+ "interface":"eth-rt6"
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16060":{
+ "inLabel":16060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":0,
+ "installed":true,
+ "nexthop":"10.0.8.6"
+ }
+ ]
+ },
+ "16061":{
+ "inLabel":16061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":2,
+ "installed":true,
+ "interface":"eth-rt6"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt5/step8/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt5/step8/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..7cdaabf53f
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step8/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step4/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt5/step9/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt5/step9/show_ip_route.ref
new file mode 100644
index 0000000000..cc37894d67
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step9/show_ip_route.ref
@@ -0,0 +1,319 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17010
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17010
+ ]
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17020
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17020
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17030
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 18040
+ ]
+ }
+ ]
+ }
+ ],
+ "6.6.6.6\/32":[
+ {
+ "prefix":"6.6.6.6\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 3
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1"
+ },
+ {
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+ "active":true
+ },
+ {
+ "ip":"10.0.5.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-2"
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.8.6",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt5/step9/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt5/step9/show_ipv6_route.ref
new file mode 100644
index 0000000000..c02d3cfaea
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step9/show_ipv6_route.ref
@@ -0,0 +1,139 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17011
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17011
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17021
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-2",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3-1",
+ "active":true,
+ "labels":[
+ 17031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 18041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::6\/128":[
+ {
+ "prefix":"2001:db8:1000::6\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true,
+ "labels":[
+ 3
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt5/step9/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt5/step9/show_mpls_table.ref
new file mode 100644
index 0000000000..e43ef6671d
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step9/show_mpls_table.ref
@@ -0,0 +1,180 @@
+{
+ "16010":{
+ "inLabel":16010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17010,
+ "installed":true,
+ "nexthop":"10.0.5.3"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17010,
+ "installed":true,
+ "nexthop":"10.0.4.3"
+ }
+ ]
+ },
+ "16011":{
+ "inLabel":16011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17011,
+ "installed":true,
+ "interface":"eth-rt3-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17011,
+ "installed":true,
+ "interface":"eth-rt3-1"
+ }
+ ]
+ },
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17020,
+ "installed":true,
+ "nexthop":"10.0.5.3"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17020,
+ "installed":true,
+ "nexthop":"10.0.4.3"
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17021,
+ "installed":true,
+ "interface":"eth-rt3-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17021,
+ "installed":true,
+ "interface":"eth-rt3-1"
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.5.3"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17030,
+ "installed":true,
+ "nexthop":"10.0.4.3"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-rt3-2"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":17031,
+ "installed":true,
+ "interface":"eth-rt3-1"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":18040,
+ "installed":true,
+ "nexthop":"10.0.8.6"
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":18041,
+ "installed":true,
+ "interface":"eth-rt6"
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true
+ }
+ ]
+ },
+ "16060":{
+ "inLabel":16060,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+ "nexthop":"10.0.8.6"
+ }
+ ]
+ },
+ "16061":{
+ "inLabel":16061,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+ "interface":"eth-rt6"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt5/step9/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt5/step9/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..7cdaabf53f
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/step9/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step4/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt5/zebra.conf b/tests/topotests/isis-sr-topo1/rt5/zebra.conf
new file mode 100644
index 0000000000..4cfea1a59f
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt5/zebra.conf
@@ -0,0 +1,28 @@
+log file zebra.log
+!
+hostname rt5
+!
+debug zebra kernel
+debug zebra packet
+debug zebra mpls
+!
+interface lo
+ ip address 5.5.5.5/32
+ ipv6 address 2001:db8:1000::5/128
+!
+interface eth-rt3-1
+ ip address 10.0.4.5/24
+!
+interface eth-rt3-2
+ ip address 10.0.5.5/24
+!
+interface eth-rt4
+ ip address 10.0.6.5/24
+!
+interface eth-rt6
+ ip address 10.0.8.5/24
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-sr-topo1/rt6/isisd.conf b/tests/topotests/isis-sr-topo1/rt6/isisd.conf
new file mode 100644
index 0000000000..16c34dfae6
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/isisd.conf
@@ -0,0 +1,36 @@
+hostname rt6
+log file isisd.log
+!
+debug isis events
+debug isis route-events
+debug isis spf-events
+debug isis sr-events
+debug isis lsp-gen
+!
+interface lo
+ ip router isis 1
+ ipv6 router isis 1
+ isis passive
+!
+interface eth-rt4
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+!
+interface eth-rt5
+ ip router isis 1
+ ipv6 router isis 1
+ isis network point-to-point
+ isis hello-multiplier 3
+!
+router isis 1
+ net 49.0000.0000.0000.0006.00
+ is-type level-1
+ topology ipv6-unicast
+ segment-routing on
+ segment-routing global-block 16000 23999
+ segment-routing node-msd 8
+ segment-routing prefix 6.6.6.6/32 index 60 explicit-null
+ segment-routing prefix 2001:db8:1000::6/128 index 61 explicit-null
+!
diff --git a/tests/topotests/isis-sr-topo1/rt6/step1/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt6/step1/show_ip_route.ref
new file mode 100644
index 0000000000..324b71f7b8
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step1/show_ip_route.ref
@@ -0,0 +1,291 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16010
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16010
+ ]
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16030
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16050
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4"
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt6/step1/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt6/step1/show_ipv6_route.ref
new file mode 100644
index 0000000000..eee9dea4d3
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step1/show_ipv6_route.ref
@@ -0,0 +1,121 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16011
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16011
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16051
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt6/step1/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt6/step1/show_mpls_table.ref
new file mode 100644
index 0000000000..970251fe8a
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step1/show_mpls_table.ref
@@ -0,0 +1,134 @@
+{
+ "16010":{
+ "inLabel":16010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16010,
+ "installed":true,
+ "nexthop":"10.0.7.4"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16010,
+ "installed":true,
+ "nexthop":"10.0.8.5"
+ }
+ ]
+ },
+ "16011":{
+ "inLabel":16011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16011,
+ "installed":true,
+ "interface":"eth-rt4"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16011,
+ "installed":true,
+ "interface":"eth-rt5"
+ }
+ ]
+ },
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.7.4"
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-rt4"
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16030,
+ "installed":true,
+ "nexthop":"10.0.8.5"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16031,
+ "installed":true,
+ "interface":"eth-rt5"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.7.4"
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-rt4"
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16050,
+ "installed":true,
+ "nexthop":"10.0.8.5"
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16051,
+ "installed":true,
+ "interface":"eth-rt5"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt6/step1/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt6/step1/show_yang_interface_isis_adjacencies.ref
new file mode 100644
index 0000000000..49c40a471c
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step1/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1,46 @@
+{
+ "frr-interface:lib": {
+ "interface": [
+ {
+ "name": "eth-rt4",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0004",
+ "neighbor-extended-circuit-id": 0,
+ "hold-timer": 9,
+ "neighbor-priority": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ },
+ {
+ "name": "eth-rt5",
+ "vrf": "default",
+ "state": {
+ "frr-isisd:isis": {
+ "adjacencies": {
+ "adjacency": [
+ {
+ "neighbor-sys-type": "level-1",
+ "neighbor-sysid": "0000.0000.0005",
+ "neighbor-extended-circuit-id": 0,
+ "hold-timer": 9,
+ "neighbor-priority": 0,
+ "state": "up"
+ }
+ ]
+ }
+ }
+ }
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt6/step10/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt6/step10/show_ip_route.ref
new file mode 100644
index 0000000000..9d0c331ff2
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step10/show_ip_route.ref
@@ -0,0 +1,284 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16010
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16010
+ ]
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16030
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16050
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4"
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt6/step10/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt6/step10/show_ipv6_route.ref
new file mode 100644
index 0000000000..eee9dea4d3
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step10/show_ipv6_route.ref
@@ -0,0 +1,121 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16011
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16011
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16051
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt6/step10/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt6/step10/show_mpls_table.ref
new file mode 100644
index 0000000000..a79406b300
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step10/show_mpls_table.ref
@@ -0,0 +1,134 @@
+{
+ "18010":{
+ "inLabel":18010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16010,
+ "installed":true,
+ "nexthop":"10.0.8.5"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16010,
+ "installed":true,
+ "nexthop":"10.0.7.4"
+ }
+ ]
+ },
+ "18011":{
+ "inLabel":18011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16011,
+ "installed":true,
+ "interface":"eth-rt5"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16011,
+ "installed":true,
+ "interface":"eth-rt4"
+ }
+ ]
+ },
+ "18020":{
+ "inLabel":18020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.7.4"
+ }
+ ]
+ },
+ "18021":{
+ "inLabel":18021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-rt4"
+ }
+ ]
+ },
+ "18030":{
+ "inLabel":18030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16030,
+ "installed":true,
+ "nexthop":"10.0.8.5"
+ }
+ ]
+ },
+ "18031":{
+ "inLabel":18031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16031,
+ "installed":true,
+ "interface":"eth-rt5"
+ }
+ ]
+ },
+ "18040":{
+ "inLabel":18040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.7.4"
+ }
+ ]
+ },
+ "18041":{
+ "inLabel":18041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-rt4"
+ }
+ ]
+ },
+ "18050":{
+ "inLabel":18050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16050,
+ "installed":true,
+ "nexthop":"10.0.8.5"
+ }
+ ]
+ },
+ "18051":{
+ "inLabel":18051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16051,
+ "installed":true,
+ "interface":"eth-rt5"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt6/step10/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt6/step10/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..0879b84d23
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step10/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step1/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt6/step2/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt6/step2/show_ip_route.ref
new file mode 100644
index 0000000000..e4df0d846e
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step2/show_ip_route.ref
@@ -0,0 +1,284 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16010
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16010
+ ]
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16030
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16050
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4"
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt6/step2/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt6/step2/show_ipv6_route.ref
new file mode 100644
index 0000000000..eee9dea4d3
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step2/show_ipv6_route.ref
@@ -0,0 +1,121 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16011
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16011
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16051
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt6/step2/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt6/step2/show_mpls_table.ref
new file mode 100644
index 0000000000..970251fe8a
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step2/show_mpls_table.ref
@@ -0,0 +1,134 @@
+{
+ "16010":{
+ "inLabel":16010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16010,
+ "installed":true,
+ "nexthop":"10.0.7.4"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16010,
+ "installed":true,
+ "nexthop":"10.0.8.5"
+ }
+ ]
+ },
+ "16011":{
+ "inLabel":16011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16011,
+ "installed":true,
+ "interface":"eth-rt4"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16011,
+ "installed":true,
+ "interface":"eth-rt5"
+ }
+ ]
+ },
+ "16020":{
+ "inLabel":16020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.7.4"
+ }
+ ]
+ },
+ "16021":{
+ "inLabel":16021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-rt4"
+ }
+ ]
+ },
+ "16030":{
+ "inLabel":16030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16030,
+ "installed":true,
+ "nexthop":"10.0.8.5"
+ }
+ ]
+ },
+ "16031":{
+ "inLabel":16031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16031,
+ "installed":true,
+ "interface":"eth-rt5"
+ }
+ ]
+ },
+ "16040":{
+ "inLabel":16040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.7.4"
+ }
+ ]
+ },
+ "16041":{
+ "inLabel":16041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-rt4"
+ }
+ ]
+ },
+ "16050":{
+ "inLabel":16050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16050,
+ "installed":true,
+ "nexthop":"10.0.8.5"
+ }
+ ]
+ },
+ "16051":{
+ "inLabel":16051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16051,
+ "installed":true,
+ "interface":"eth-rt5"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt6/step2/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt6/step2/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..0879b84d23
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step2/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step1/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt6/step3/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt6/step3/show_ip_route.ref
new file mode 100644
index 0000000000..2c63c08510
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step3/show_ip_route.ref
@@ -0,0 +1,2 @@
+{
+}
diff --git a/tests/topotests/isis-sr-topo1/rt6/step3/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt6/step3/show_ipv6_route.ref
new file mode 100644
index 0000000000..2c63c08510
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step3/show_ipv6_route.ref
@@ -0,0 +1,2 @@
+{
+}
diff --git a/tests/topotests/isis-sr-topo1/rt6/step3/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt6/step3/show_mpls_table.ref
new file mode 100644
index 0000000000..2c63c08510
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step3/show_mpls_table.ref
@@ -0,0 +1,2 @@
+{
+}
diff --git a/tests/topotests/isis-sr-topo1/rt6/step3/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt6/step3/show_yang_interface_isis_adjacencies.ref
new file mode 100644
index 0000000000..0db3279e44
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step3/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1,3 @@
+{
+
+}
diff --git a/tests/topotests/isis-sr-topo1/rt6/step4/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt6/step4/show_ip_route.ref
new file mode 100644
index 0000000000..e4df0d846e
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step4/show_ip_route.ref
@@ -0,0 +1,284 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16010
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16010
+ ]
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16030
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16050
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4"
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt6/step4/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt6/step4/show_ipv6_route.ref
new file mode 100644
index 0000000000..eee9dea4d3
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step4/show_ipv6_route.ref
@@ -0,0 +1,121 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16011
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16011
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16051
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt6/step4/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt6/step4/show_mpls_table.ref
new file mode 100644
index 0000000000..a79406b300
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step4/show_mpls_table.ref
@@ -0,0 +1,134 @@
+{
+ "18010":{
+ "inLabel":18010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16010,
+ "installed":true,
+ "nexthop":"10.0.8.5"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16010,
+ "installed":true,
+ "nexthop":"10.0.7.4"
+ }
+ ]
+ },
+ "18011":{
+ "inLabel":18011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16011,
+ "installed":true,
+ "interface":"eth-rt5"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16011,
+ "installed":true,
+ "interface":"eth-rt4"
+ }
+ ]
+ },
+ "18020":{
+ "inLabel":18020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.7.4"
+ }
+ ]
+ },
+ "18021":{
+ "inLabel":18021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-rt4"
+ }
+ ]
+ },
+ "18030":{
+ "inLabel":18030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16030,
+ "installed":true,
+ "nexthop":"10.0.8.5"
+ }
+ ]
+ },
+ "18031":{
+ "inLabel":18031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16031,
+ "installed":true,
+ "interface":"eth-rt5"
+ }
+ ]
+ },
+ "18040":{
+ "inLabel":18040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.7.4"
+ }
+ ]
+ },
+ "18041":{
+ "inLabel":18041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-rt4"
+ }
+ ]
+ },
+ "18050":{
+ "inLabel":18050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16050,
+ "installed":true,
+ "nexthop":"10.0.8.5"
+ }
+ ]
+ },
+ "18051":{
+ "inLabel":18051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16051,
+ "installed":true,
+ "interface":"eth-rt5"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt6/step4/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt6/step4/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..0879b84d23
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step4/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step1/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt6/step5/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt6/step5/show_ip_route.ref
new file mode 100644
index 0000000000..c200a9f476
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step5/show_ip_route.ref
@@ -0,0 +1,266 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4"
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt6/step5/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt6/step5/show_ipv6_route.ref
new file mode 100644
index 0000000000..2bf4b70be8
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step5/show_ipv6_route.ref
@@ -0,0 +1,103 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt6/step5/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt6/step5/show_mpls_table.ref
new file mode 100644
index 0000000000..2c63c08510
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step5/show_mpls_table.ref
@@ -0,0 +1,2 @@
+{
+}
diff --git a/tests/topotests/isis-sr-topo1/rt6/step5/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt6/step5/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..0879b84d23
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step5/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step1/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt6/step6/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt6/step6/show_ip_route.ref
new file mode 100644
index 0000000000..e4df0d846e
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step6/show_ip_route.ref
@@ -0,0 +1,284 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16010
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16010
+ ]
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16030
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16050
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4"
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt6/step6/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt6/step6/show_ipv6_route.ref
new file mode 100644
index 0000000000..eee9dea4d3
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step6/show_ipv6_route.ref
@@ -0,0 +1,121 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16011
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16011
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16051
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt6/step6/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt6/step6/show_mpls_table.ref
new file mode 100644
index 0000000000..a79406b300
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step6/show_mpls_table.ref
@@ -0,0 +1,134 @@
+{
+ "18010":{
+ "inLabel":18010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16010,
+ "installed":true,
+ "nexthop":"10.0.8.5"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16010,
+ "installed":true,
+ "nexthop":"10.0.7.4"
+ }
+ ]
+ },
+ "18011":{
+ "inLabel":18011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16011,
+ "installed":true,
+ "interface":"eth-rt5"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16011,
+ "installed":true,
+ "interface":"eth-rt4"
+ }
+ ]
+ },
+ "18020":{
+ "inLabel":18020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.7.4"
+ }
+ ]
+ },
+ "18021":{
+ "inLabel":18021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-rt4"
+ }
+ ]
+ },
+ "18030":{
+ "inLabel":18030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16030,
+ "installed":true,
+ "nexthop":"10.0.8.5"
+ }
+ ]
+ },
+ "18031":{
+ "inLabel":18031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16031,
+ "installed":true,
+ "interface":"eth-rt5"
+ }
+ ]
+ },
+ "18040":{
+ "inLabel":18040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.7.4"
+ }
+ ]
+ },
+ "18041":{
+ "inLabel":18041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-rt4"
+ }
+ ]
+ },
+ "18050":{
+ "inLabel":18050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16050,
+ "installed":true,
+ "nexthop":"10.0.8.5"
+ }
+ ]
+ },
+ "18051":{
+ "inLabel":18051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16051,
+ "installed":true,
+ "interface":"eth-rt5"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt6/step6/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt6/step6/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..0879b84d23
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step6/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step1/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt6/step7/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt6/step7/show_ip_route.ref
new file mode 100644
index 0000000000..b21e5db928
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step7/show_ip_route.ref
@@ -0,0 +1,278 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16030
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16050
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4"
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt6/step7/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt6/step7/show_ipv6_route.ref
new file mode 100644
index 0000000000..dfbb1954b8
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step7/show_ipv6_route.ref
@@ -0,0 +1,115 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16051
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt6/step7/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt6/step7/show_mpls_table.ref
new file mode 100644
index 0000000000..43d771bcbd
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step7/show_mpls_table.ref
@@ -0,0 +1,98 @@
+{
+ "18020":{
+ "inLabel":18020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.7.4"
+ }
+ ]
+ },
+ "18021":{
+ "inLabel":18021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-rt4"
+ }
+ ]
+ },
+ "18030":{
+ "inLabel":18030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16030,
+ "installed":true,
+ "nexthop":"10.0.8.5"
+ }
+ ]
+ },
+ "18031":{
+ "inLabel":18031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16031,
+ "installed":true,
+ "interface":"eth-rt5"
+ }
+ ]
+ },
+ "18040":{
+ "inLabel":18040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.7.4"
+ }
+ ]
+ },
+ "18041":{
+ "inLabel":18041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-rt4"
+ }
+ ]
+ },
+ "18050":{
+ "inLabel":18050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16050,
+ "installed":true,
+ "nexthop":"10.0.8.5"
+ }
+ ]
+ },
+ "18051":{
+ "inLabel":18051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16051,
+ "installed":true,
+ "interface":"eth-rt5"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt6/step7/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt6/step7/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..0879b84d23
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step7/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step1/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt6/step8/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt6/step8/show_ip_route.ref
new file mode 100644
index 0000000000..e4df0d846e
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step8/show_ip_route.ref
@@ -0,0 +1,284 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16010
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16010
+ ]
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16030
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16050
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4"
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt6/step8/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt6/step8/show_ipv6_route.ref
new file mode 100644
index 0000000000..eee9dea4d3
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step8/show_ipv6_route.ref
@@ -0,0 +1,121 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16011
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16011
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16051
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt6/step8/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt6/step8/show_mpls_table.ref
new file mode 100644
index 0000000000..a79406b300
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step8/show_mpls_table.ref
@@ -0,0 +1,134 @@
+{
+ "18010":{
+ "inLabel":18010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16010,
+ "installed":true,
+ "nexthop":"10.0.8.5"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16010,
+ "installed":true,
+ "nexthop":"10.0.7.4"
+ }
+ ]
+ },
+ "18011":{
+ "inLabel":18011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16011,
+ "installed":true,
+ "interface":"eth-rt5"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16011,
+ "installed":true,
+ "interface":"eth-rt4"
+ }
+ ]
+ },
+ "18020":{
+ "inLabel":18020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.7.4"
+ }
+ ]
+ },
+ "18021":{
+ "inLabel":18021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-rt4"
+ }
+ ]
+ },
+ "18030":{
+ "inLabel":18030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16030,
+ "installed":true,
+ "nexthop":"10.0.8.5"
+ }
+ ]
+ },
+ "18031":{
+ "inLabel":18031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16031,
+ "installed":true,
+ "interface":"eth-rt5"
+ }
+ ]
+ },
+ "18040":{
+ "inLabel":18040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.7.4"
+ }
+ ]
+ },
+ "18041":{
+ "inLabel":18041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-rt4"
+ }
+ ]
+ },
+ "18050":{
+ "inLabel":18050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16050,
+ "installed":true,
+ "nexthop":"10.0.8.5"
+ }
+ ]
+ },
+ "18051":{
+ "inLabel":18051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16051,
+ "installed":true,
+ "interface":"eth-rt5"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt6/step8/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt6/step8/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..0879b84d23
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step8/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step1/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt6/step9/show_ip_route.ref b/tests/topotests/isis-sr-topo1/rt6/step9/show_ip_route.ref
new file mode 100644
index 0000000000..e4df0d846e
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step9/show_ip_route.ref
@@ -0,0 +1,284 @@
+{
+ "1.1.1.1\/32":[
+ {
+ "prefix":"1.1.1.1\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16010
+ ]
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16010
+ ]
+ }
+ ]
+ }
+ ],
+ "2.2.2.2\/32":[
+ {
+ "prefix":"2.2.2.2\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16020
+ ]
+ }
+ ]
+ }
+ ],
+ "3.3.3.3\/32":[
+ {
+ "prefix":"3.3.3.3\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16030
+ ]
+ }
+ ]
+ }
+ ],
+ "4.4.4.4\/32":[
+ {
+ "prefix":"4.4.4.4\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16040
+ ]
+ }
+ ]
+ }
+ ],
+ "5.5.5.5\/32":[
+ {
+ "prefix":"5.5.5.5\/32",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16050
+ ]
+ }
+ ]
+ }
+ ],
+ "10.0.1.0\/24":[
+ {
+ "prefix":"10.0.1.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ },
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.2.0\/24":[
+ {
+ "prefix":"10.0.2.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.3.0\/24":[
+ {
+ "prefix":"10.0.3.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.4.0\/24":[
+ {
+ "prefix":"10.0.4.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.5.0\/24":[
+ {
+ "prefix":"10.0.5.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.6.0\/24":[
+ {
+ "prefix":"10.0.6.0\/24",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.7.0\/24":[
+ {
+ "prefix":"10.0.7.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4"
+ }
+ ]
+ }
+ ],
+ "10.0.8.0\/24":[
+ {
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "distance":115,
+ "metric":20,
+ "nexthops":[
+ {
+ "ip":"10.0.8.5",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt6/step9/show_ipv6_route.ref b/tests/topotests/isis-sr-topo1/rt6/step9/show_ipv6_route.ref
new file mode 100644
index 0000000000..eee9dea4d3
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step9/show_ipv6_route.ref
@@ -0,0 +1,121 @@
+{
+ "2001:db8:1000::1\/128":[
+ {
+ "prefix":"2001:db8:1000::1\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16011
+ ]
+ },
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16011
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::2\/128":[
+ {
+ "prefix":"2001:db8:1000::2\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16021
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::3\/128":[
+ {
+ "prefix":"2001:db8:1000::3\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16031
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::4\/128":[
+ {
+ "prefix":"2001:db8:1000::4\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+ 16041
+ ]
+ }
+ ]
+ }
+ ],
+ "2001:db8:1000::5\/128":[
+ {
+ "prefix":"2001:db8:1000::5\/128",
+ "protocol":"isis",
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+ "metric":20,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "labels":[
+ 16051
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/isis-sr-topo1/rt6/step9/show_mpls_table.ref b/tests/topotests/isis-sr-topo1/rt6/step9/show_mpls_table.ref
new file mode 100644
index 0000000000..a79406b300
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step9/show_mpls_table.ref
@@ -0,0 +1,134 @@
+{
+ "18010":{
+ "inLabel":18010,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16010,
+ "installed":true,
+ "nexthop":"10.0.8.5"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16010,
+ "installed":true,
+ "nexthop":"10.0.7.4"
+ }
+ ]
+ },
+ "18011":{
+ "inLabel":18011,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16011,
+ "installed":true,
+ "interface":"eth-rt5"
+ },
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16011,
+ "installed":true,
+ "interface":"eth-rt4"
+ }
+ ]
+ },
+ "18020":{
+ "inLabel":18020,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+ "nexthop":"10.0.7.4"
+ }
+ ]
+ },
+ "18021":{
+ "inLabel":18021,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+ "interface":"eth-rt4"
+ }
+ ]
+ },
+ "18030":{
+ "inLabel":18030,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16030,
+ "installed":true,
+ "nexthop":"10.0.8.5"
+ }
+ ]
+ },
+ "18031":{
+ "inLabel":18031,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16031,
+ "installed":true,
+ "interface":"eth-rt5"
+ }
+ ]
+ },
+ "18040":{
+ "inLabel":18040,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16040,
+ "installed":true,
+ "nexthop":"10.0.7.4"
+ }
+ ]
+ },
+ "18041":{
+ "inLabel":18041,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16041,
+ "installed":true,
+ "interface":"eth-rt4"
+ }
+ ]
+ },
+ "18050":{
+ "inLabel":18050,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16050,
+ "installed":true,
+ "nexthop":"10.0.8.5"
+ }
+ ]
+ },
+ "18051":{
+ "inLabel":18051,
+ "installed":true,
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16051,
+ "installed":true,
+ "interface":"eth-rt5"
+ }
+ ]
+ }
+}
diff --git a/tests/topotests/isis-sr-topo1/rt6/step9/show_yang_interface_isis_adjacencies.ref b/tests/topotests/isis-sr-topo1/rt6/step9/show_yang_interface_isis_adjacencies.ref
new file mode 120000
index 0000000000..0879b84d23
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/step9/show_yang_interface_isis_adjacencies.ref
@@ -0,0 +1 @@
+../step1/show_yang_interface_isis_adjacencies.ref \ No newline at end of file
diff --git a/tests/topotests/isis-sr-topo1/rt6/zebra.conf b/tests/topotests/isis-sr-topo1/rt6/zebra.conf
new file mode 100644
index 0000000000..6084010a93
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/rt6/zebra.conf
@@ -0,0 +1,22 @@
+log file zebra.log
+!
+hostname rt6
+!
+debug zebra kernel
+debug zebra packet
+debug zebra mpls
+!
+interface lo
+ ip address 6.6.6.6/32
+ ipv6 address 2001:db8:1000::6/128
+!
+interface eth-rt4
+ ip address 10.0.7.6/24
+!
+interface eth-rt5
+ ip address 10.0.8.6/24
+!
+ip forwarding
+!
+line vty
+!
diff --git a/tests/topotests/isis-sr-topo1/test_isis_sr_topo1.py b/tests/topotests/isis-sr-topo1/test_isis_sr_topo1.py
new file mode 100755
index 0000000000..72bc96e4d0
--- /dev/null
+++ b/tests/topotests/isis-sr-topo1/test_isis_sr_topo1.py
@@ -0,0 +1,915 @@
+#!/usr/bin/env python
+
+#
+# test_isis_sr_topo1.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2019 by
+# Network Device Education Foundation, Inc. ("NetDEF")
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+test_isis_sr_topo1.py:
+
+ +---------+
+ | |
+ | RT1 |
+ | 1.1.1.1 |
+ | |
+ +---------+
+ |eth-sw1
+ |
+ |
+ |
+ +---------+ | +---------+
+ | | | | |
+ | RT2 |eth-sw1 | eth-sw1| RT3 |
+ | 2.2.2.2 +----------+----------+ 3.3.3.3 |
+ | | 10.0.1.0/24 | |
+ +---------+ +---------+
+ eth-rt4-1| |eth-rt4-2 eth-rt5-1| |eth-rt5-2
+ | | | |
+ 10.0.2.0/24| |10.0.3.0/24 10.0.4.0/24| |10.0.5.0/24
+ | | | |
+ eth-rt2-1| |eth-rt2-2 eth-rt3-1| |eth-rt3-2
+ +---------+ +---------+
+ | | | |
+ | RT4 | 10.0.6.0/24 | RT5 |
+ | 4.4.4.4 +---------------------+ 5.5.5.5 |
+ | |eth-rt5 eth-rt4| |
+ +---------+ +---------+
+ eth-rt6| |eth-rt6
+ | |
+ 10.0.7.0/24| |10.0.8.0/24
+ | +---------+ |
+ | | | |
+ | | RT6 | |
+ +----------+ 6.6.6.6 +-----------+
+ eth-rt4| |eth-rt5
+ +---------+
+"""
+
+import os
+import sys
+import pytest
+import json
+import re
+from time import sleep
+from functools import partial
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, '../'))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+# Required to instantiate the topology builder class.
+from mininet.topo import Topo
+
+class TemplateTopo(Topo):
+ "Test topology builder"
+ def build(self, *_args, **_opts):
+ "Build function"
+ tgen = get_topogen(self)
+
+ #
+ # Define FRR Routers
+ #
+ for router in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ tgen.add_router(router)
+
+ #
+ # Define connections
+ #
+ switch = tgen.add_switch('s1')
+ switch.add_link(tgen.gears['rt1'], nodeif="eth-sw1")
+ switch.add_link(tgen.gears['rt2'], nodeif="eth-sw1")
+ switch.add_link(tgen.gears['rt3'], nodeif="eth-sw1")
+
+ switch = tgen.add_switch('s2')
+ switch.add_link(tgen.gears['rt2'], nodeif="eth-rt4-1")
+ switch.add_link(tgen.gears['rt4'], nodeif="eth-rt2-1")
+
+ switch = tgen.add_switch('s3')
+ switch.add_link(tgen.gears['rt2'], nodeif="eth-rt4-2")
+ switch.add_link(tgen.gears['rt4'], nodeif="eth-rt2-2")
+
+ switch = tgen.add_switch('s4')
+ switch.add_link(tgen.gears['rt3'], nodeif="eth-rt5-1")
+ switch.add_link(tgen.gears['rt5'], nodeif="eth-rt3-1")
+
+ switch = tgen.add_switch('s5')
+ switch.add_link(tgen.gears['rt3'], nodeif="eth-rt5-2")
+ switch.add_link(tgen.gears['rt5'], nodeif="eth-rt3-2")
+
+ switch = tgen.add_switch('s6')
+ switch.add_link(tgen.gears['rt4'], nodeif="eth-rt5")
+ switch.add_link(tgen.gears['rt5'], nodeif="eth-rt4")
+
+ switch = tgen.add_switch('s7')
+ switch.add_link(tgen.gears['rt4'], nodeif="eth-rt6")
+ switch.add_link(tgen.gears['rt6'], nodeif="eth-rt4")
+
+ switch = tgen.add_switch('s8')
+ switch.add_link(tgen.gears['rt5'], nodeif="eth-rt6")
+ switch.add_link(tgen.gears['rt6'], nodeif="eth-rt5")
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+ tgen = Topogen(TemplateTopo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ # For all registered routers, load the zebra configuration file
+ for rname, router in router_list.iteritems():
+ router.load_config(
+ TopoRouter.RD_ZEBRA,
+ os.path.join(CWD, '{}/zebra.conf'.format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_ISIS,
+ os.path.join(CWD, '{}/isisd.conf'.format(rname))
+ )
+
+ tgen.start_router()
+
+def teardown_module(mod):
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+
+ # This function tears down the whole topology.
+ tgen.stop_topology()
+
+def router_compare_json_output(rname, command, reference):
+ "Compare router JSON output"
+
+ logger.info('Comparing router "%s" "%s" output', rname, command)
+
+ tgen = get_topogen()
+ filename = '{}/{}/{}'.format(CWD, rname, reference)
+ expected = json.loads(open(filename).read())
+
+ # Run test function until we get an result. Wait at most 60 seconds.
+ test_func = partial(topotest.router_json_cmp,
+ tgen.gears[rname], command, expected)
+ _, diff = topotest.run_and_expect(test_func, None, count=120, wait=0.5)
+ assertmsg = '"{}" JSON output mismatches the expected result'.format(rname)
+ assert diff is None, assertmsg
+
+#
+# Step 1
+#
+# Test initial network convergence
+#
+def test_isis_adjacencies_step1():
+ logger.info("Test (step 1): check IS-IS adjacencies")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show yang operational-data /frr-interface:lib isisd",
+ "step1/show_yang_interface_isis_adjacencies.ref")
+
+def test_rib_ipv4_step1():
+ logger.info("Test (step 1): verify IPv4 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show ip route isis json",
+ "step1/show_ip_route.ref")
+
+def test_rib_ipv6_step1():
+ logger.info("Test (step 1): verify IPv6 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show ipv6 route isis json",
+ "step1/show_ipv6_route.ref")
+
+def test_mpls_lib_step1():
+ logger.info("Test (step 1): verify MPLS LIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show mpls table json",
+ "step1/show_mpls_table.ref")
+
+#
+# Step 2
+#
+# Action(s):
+# -Disable IS-IS on the eth-rt5 interface on rt4
+#
+# Expected changes:
+# -rt4 should uninstall the Adj-SIDs pointing to rt5
+# -rt5 should uninstall the Adj-SIDs pointing to rt4
+# -rt2 should reinstall rt5's Prefix-SIDs (2 nexthops deleted)
+# -rt3 should reinstall rt4's Prefix-SIDs (2 nexthops deleted)
+# -rt4 should reinstall rt3's Prefix-SIDs (1 nexthop deleted)
+# -rt4 should reinstall rt5's Prefix-SIDs (1 nexthop changed)
+# -rt5 should reinstall rt2's Prefix-SIDs (1 nexthop deleted)
+# -rt5 should reinstall rt4's Prefix-SIDs (1 nexthop changed)
+#
+def test_isis_adjacencies_step2():
+ logger.info("Test (step 2): check IS-IS adjacencies")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info('Disabling IS-IS on the eth-rt5 interface on rt4')
+ tgen.net['rt4'].cmd('vtysh -c "conf t" -c "interface eth-rt5" -c "no ip router isis 1"')
+ tgen.net['rt4'].cmd('vtysh -c "conf t" -c "interface eth-rt5" -c "no ipv6 router isis 1"')
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show yang operational-data /frr-interface:lib isisd",
+ "step2/show_yang_interface_isis_adjacencies.ref")
+
+def test_rib_ipv4_step2():
+ logger.info("Test (step 2): verify IPv4 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show ip route isis json",
+ "step2/show_ip_route.ref")
+
+def test_rib_ipv6_step2():
+ logger.info("Test (step 2): verify IPv6 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show ipv6 route isis json",
+ "step2/show_ipv6_route.ref")
+
+def test_mpls_lib_step2():
+ logger.info("Test (step 2): verify MPLS LIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show mpls table json",
+ "step2/show_mpls_table.ref")
+
+#
+# Step 3
+#
+# Action(s):
+# -Shut down the eth-rt4 interface on rt6
+# -Shut down the eth-rt5 interface on rt6
+#
+# Expected changes:
+# -All routers should uninstall rt6's Prefix-SIDs
+# -rt4 and rt5 should uninstall the Adj-SIDs pointing to rt6
+# -rt4 should reconverge rt5's Prefix-SIDs through rt2 using ECMP
+# -rt5 should reconverge rt4's Prefix-SIDs through rt3 using ECMP
+# -rt6 should uninstall all its IS-IS routes, Prefix-SIDs and Adj-SIDs
+#
+def test_isis_adjacencies_step3():
+ logger.info("Test (step 3): check IS-IS adjacencies")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info('Shutting down the eth-rt4 interface on rt6')
+ tgen.net['rt6'].cmd('vtysh -c "conf t" -c "interface eth-rt4" -c "shutdown"')
+ logger.info('Shutting down the eth-rt5 interface on rt6')
+ tgen.net['rt6'].cmd('vtysh -c "conf t" -c "interface eth-rt5" -c "shutdown"')
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show yang operational-data /frr-interface:lib isisd",
+ "step3/show_yang_interface_isis_adjacencies.ref")
+
+def test_rib_ipv4_step3():
+ logger.info("Test (step 3): verify IPv4 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show ip route isis json",
+ "step3/show_ip_route.ref")
+
+def test_rib_ipv6_step3():
+ logger.info("Test (step 3): verify IPv6 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show ipv6 route isis json",
+ "step3/show_ipv6_route.ref")
+
+def test_mpls_lib_step3():
+ logger.info("Test (step 3): verify MPLS LIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show mpls table json",
+ "step3/show_mpls_table.ref")
+
+#
+# Step 4
+#
+# Action(s):
+# -Bring up the eth-rt4 interface on rt6
+# -Bring up the eth-rt5 interface on rt6
+# -Change rt6's SRGB
+#
+# Expected changes:
+# -All routers should install rt6's Prefix-SIDs
+# -rt4 and rt5 should install Adj-SIDs for rt6
+# -rt4 should reconverge rt5's Prefix-SIDs through rt6 using the new SRGB
+# -rt5 should reconverge rt4's Prefix-SIDs through rt6 using the new SRGB
+# -rt6 should reinstall all IS-IS routes and Prefix-SIDs from the network, and Adj-SIDs for rt4 and rt5
+#
+def test_isis_adjacencies_step4():
+ logger.info("Test (step 4): check IS-IS adjacencies")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info('Bringing up the eth-rt4 interface on rt6')
+ tgen.net['rt6'].cmd('vtysh -c "conf t" -c "interface eth-rt4" -c "no shutdown"')
+ logger.info('Bringing up the eth-rt5 interface on rt6')
+ tgen.net['rt6'].cmd('vtysh -c "conf t" -c "interface eth-rt5" -c "no shutdown"')
+ logger.info('Changing rt6\'s SRGB')
+ tgen.net['rt6'].cmd('vtysh -c "conf t" -c "router isis 1" -c "segment-routing global-block 18000 25999"')
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show yang operational-data /frr-interface:lib isisd",
+ "step4/show_yang_interface_isis_adjacencies.ref")
+
+def test_rib_ipv4_step4():
+ logger.info("Test (step 4): verify IPv4 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show ip route isis json",
+ "step4/show_ip_route.ref")
+
+def test_rib_ipv6_step4():
+ logger.info("Test (step 4): verify IPv6 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show ipv6 route isis json",
+ "step4/show_ipv6_route.ref")
+
+def test_mpls_lib_step4():
+ logger.info("Test (step 4): verify MPLS LIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show mpls table json",
+ "step4/show_mpls_table.ref")
+
+#
+# Step 5
+#
+# Action(s):
+# -Disable SR on rt6
+#
+# Expected changes:
+# -All routers should uninstall rt6's Prefix-SIDs
+# -rt4 should uninstall rt5's Prefix-SIDs since the nexthop router hasn't SR enabled anymore
+# -rt5 should uninstall rt4's Prefix-SIDs since the nexthop router hasn't SR enabled anymore
+# -rt6 should uninstall all Prefix-SIDs from the network, and the Adj-SIDs for rt4 and rt5
+#
+def test_isis_adjacencies_step5():
+ logger.info("Test (step 5): check IS-IS adjacencies")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info('Disabling SR on rt6')
+ tgen.net['rt6'].cmd('vtysh -c "conf t" -c "router isis 1" -c "no segment-routing on"')
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show yang operational-data /frr-interface:lib isisd",
+ "step5/show_yang_interface_isis_adjacencies.ref")
+
+def test_rib_ipv4_step5():
+ logger.info("Test (step 5): verify IPv4 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show ip route isis json",
+ "step5/show_ip_route.ref")
+
+def test_rib_ipv6_step5():
+ logger.info("Test (step 5): verify IPv6 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show ipv6 route isis json",
+ "step5/show_ipv6_route.ref")
+
+def test_mpls_lib_step5():
+ logger.info("Test (step 5): verify MPLS LIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show mpls table json",
+ "step5/show_mpls_table.ref")
+
+#
+# Step 6
+#
+# Action(s):
+# -Enable SR on rt6
+#
+# Expected changes:
+# -All routers should install rt6's Prefix-SIDs
+# -rt4 should install rt5's Prefix-SIDs through rt6
+# -rt5 should install rt4's Prefix-SIDs through rt6
+# -rt6 should install all Prefix-SIDs from the network, and Adj-SIDs for rt4 and rt5
+#
+def test_isis_adjacencies_step6():
+ logger.info("Test (step 6): check IS-IS adjacencies")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info('Enabling SR on rt6')
+ tgen.net['rt6'].cmd('vtysh -c "conf t" -c "router isis 1" -c "segment-routing on"')
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show yang operational-data /frr-interface:lib isisd",
+ "step6/show_yang_interface_isis_adjacencies.ref")
+
+def test_rib_ipv4_step6():
+ logger.info("Test (step 6): verify IPv4 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show ip route isis json",
+ "step6/show_ip_route.ref")
+
+def test_rib_ipv6_step6():
+ logger.info("Test (step 6): verify IPv6 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show ipv6 route isis json",
+ "step6/show_ipv6_route.ref")
+
+def test_mpls_lib_step6():
+ logger.info("Test (step 6): verify MPLS LIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show mpls table json",
+ "step6/show_mpls_table.ref")
+
+#
+# Step 7
+#
+# Action(s):
+# -Delete rt1's Prefix-SIDs
+#
+# Expected changes:
+# -All routers should uninstall rt1's Prefix-SIDs
+#
+def test_isis_adjacencies_step7():
+ logger.info("Test (step 7): check IS-IS adjacencies")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info('Deleting rt1\'s Prefix-SIDs')
+ tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "no segment-routing prefix 1.1.1.1/32 index 10"')
+ tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "no segment-routing prefix 2001:db8:1000::1/128 index 11"')
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show yang operational-data /frr-interface:lib isisd",
+ "step7/show_yang_interface_isis_adjacencies.ref")
+
+def test_rib_ipv4_step7():
+ logger.info("Test (step 7): verify IPv4 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show ip route isis json",
+ "step7/show_ip_route.ref")
+
+def test_rib_ipv6_step7():
+ logger.info("Test (step 7): verify IPv6 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show ipv6 route isis json",
+ "step7/show_ipv6_route.ref")
+
+def test_mpls_lib_step7():
+ logger.info("Test (step 7): verify MPLS LIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show mpls table json",
+ "step7/show_mpls_table.ref")
+
+#
+# Step 8
+#
+# Action(s):
+# -Re-add rt1's Prefix-SIDs
+#
+# Expected changes:
+# -All routers should install rt1's Prefix-SIDs
+#
+def test_isis_adjacencies_step8():
+ logger.info("Test (step 8): check IS-IS adjacencies")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info('Re-adding rt1\'s Prefix-SIDs')
+ tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "segment-routing prefix 1.1.1.1/32 index 10"')
+ tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "segment-routing prefix 2001:db8:1000::1/128 index 11"')
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show yang operational-data /frr-interface:lib isisd",
+ "step8/show_yang_interface_isis_adjacencies.ref")
+
+def test_rib_ipv4_step8():
+ logger.info("Test (step 8): verify IPv4 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show ip route isis json",
+ "step8/show_ip_route.ref")
+
+def test_rib_ipv6_step8():
+ logger.info("Test (step 8): verify IPv6 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show ipv6 route isis json",
+ "step8/show_ipv6_route.ref")
+
+def test_mpls_lib_step8():
+ logger.info("Test (step 8): verify MPLS LIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show mpls table json",
+ "step8/show_mpls_table.ref")
+
+#
+# Step 9
+#
+# Action(s):
+# -Change rt1's Prefix-SIDs to use the no-php option
+# -Change rt6's Prefix-SIDs to stop using the explicit-null option
+#
+# Expected changes:
+# -rt2 and rt3 should reinstall rt1's Prefix-SIDs accordingly
+# -rt4 and rt5 should reinstall rt6's Prefix-SIDs accordingly
+#
+def test_isis_adjacencies_step9():
+ logger.info("Test (step 9): check IS-IS adjacencies")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info('Changing rt1\'s Prefix-SIDs to use the no-php option')
+ tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "segment-routing prefix 1.1.1.1/32 index 10 no-php-flag"')
+ tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "segment-routing prefix 2001:db8:1000::1/128 index 11 no-php-flag"')
+ logger.info('Change rt6\'s Prefix-SIDs to stop using the explicit-null option')
+ tgen.net['rt6'].cmd('vtysh -c "conf t" -c "router isis 1" -c "segment-routing prefix 6.6.6.6/32 index 60"')
+ tgen.net['rt6'].cmd('vtysh -c "conf t" -c "router isis 1" -c "segment-routing prefix 2001:db8:1000::6/128 index 61"')
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show yang operational-data /frr-interface:lib isisd",
+ "step9/show_yang_interface_isis_adjacencies.ref")
+
+def test_rib_ipv4_step9():
+ logger.info("Test (step 9): verify IPv4 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show ip route isis json",
+ "step9/show_ip_route.ref")
+
+def test_rib_ipv6_step9():
+ logger.info("Test (step 9): verify IPv6 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show ipv6 route isis json",
+ "step9/show_ipv6_route.ref")
+
+def test_mpls_lib_step9():
+ logger.info("Test (step 9): verify MPLS LIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show mpls table json",
+ "step9/show_mpls_table.ref")
+
+#
+# Step 10
+#
+# Action(s):
+# -Remove the IPv4 address from rt4's eth-rt2-1 interface
+#
+# Expected changes:
+# -rt2 should uninstall the IPv4 Adj-SIDs attached to the eth-rt4-1 interface
+# -rt2 should reinstall all IPv4 Prefix-SIDs whose nexthop router is rt4 (ECMP shouldn't be used anymore)
+# -rt4 should reinstall all IPv4 Prefix-SIDs whose nexthop router is rt2 (ECMP shouldn't be used anymore)
+#
+def test_isis_adjacencies_step10():
+ logger.info("Test (step 10): check IS-IS adjacencies")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info('Removing the IPv4 address from rt4\'s eth-rt2-1 interface')
+ tgen.net['rt4'].cmd('vtysh -c "conf t" -c "interface eth-rt2-1" -c "no ip address 10.0.2.4/24"')
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show yang operational-data /frr-interface:lib isisd",
+ "step10/show_yang_interface_isis_adjacencies.ref")
+
+def test_rib_ipv4_step10():
+ logger.info("Test (step 10): verify IPv4 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show ip route isis json",
+ "step10/show_ip_route.ref")
+
+def test_rib_ipv6_step10():
+ logger.info("Test (step 10): verify IPv6 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show ipv6 route isis json",
+ "step10/show_ipv6_route.ref")
+
+def test_mpls_lib_step10():
+ logger.info("Test (step 10): verify MPLS LIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show mpls table json",
+ "step10/show_mpls_table.ref")
+
+#
+# Step 11
+#
+# Action(s):
+# -Enter invalid SR configuration
+#
+# Expected changes:
+# -All commands should be rejected
+#
+def test_isis_invalid_config_step11():
+ logger.info("Test (step 11): check if invalid configuration is rejected")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info('Entering invalid Segment Routing configuration...')
+ ret = tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "segment-routing prefix 1.1.1.1/32 index 10000"')
+ assert re.search("Configuration failed", ret) is not None, "Invalid SR configuration wasn't rejected"
+ ret = tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "segment-routing global-block 16000 14999"')
+ assert re.search("Configuration failed", ret) is not None, "Invalid SR configuration wasn't rejected"
+ ret = tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "segment-routing global-block 16000 16001"')
+ assert re.search("Configuration failed", ret) is not None, "Invalid SR configuration wasn't rejected"
+
+#
+# Step 12
+#
+# Action(s):
+# -Restore the original network setup
+#
+# Expected changes:
+# -All routes, Prefix-SIDs and Adj-SIDs should be the same as they were after the initial network convergence (step 1)
+#
+def test_isis_adjacencies_step12():
+ logger.info("Test (step 12): check IS-IS adjacencies")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info('Restoring the original network setup')
+ tgen.net['rt4'].cmd('vtysh -c "conf t" -c "interface eth-rt5" -c "ip router isis 1"')
+ tgen.net['rt4'].cmd('vtysh -c "conf t" -c "interface eth-rt5" -c "ipv6 router isis 1"')
+ tgen.net['rt6'].cmd('vtysh -c "conf t" -c "router isis 1" -c "segment-routing global-block 16000 23999"')
+ tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "segment-routing prefix 1.1.1.1/32 index 10"')
+ tgen.net['rt1'].cmd('vtysh -c "conf t" -c "router isis 1" -c "segment-routing prefix 2001:db8:1000::1/128 index 11"')
+ tgen.net['rt6'].cmd('vtysh -c "conf t" -c "router isis 1" -c "segment-routing prefix 6.6.6.6/32 index 60 explicit-null"')
+ tgen.net['rt6'].cmd('vtysh -c "conf t" -c "router isis 1" -c "segment-routing prefix 2001:db8:1000::6/128 index 61 explicit-null"')
+ tgen.net['rt4'].cmd('vtysh -c "conf t" -c "interface eth-rt2-1" -c "ip address 10.0.2.4/24"')
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show yang operational-data /frr-interface:lib isisd",
+ "step1/show_yang_interface_isis_adjacencies.ref")
+
+def test_rib_ipv4_step12():
+ logger.info("Test (step 12): verify IPv4 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show ip route isis json",
+ "step1/show_ip_route.ref")
+
+def test_rib_ipv6_step12():
+ logger.info("Test (step 12): verify IPv6 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show ipv6 route isis json",
+ "step1/show_ipv6_route.ref")
+
+def test_mpls_lib_step12():
+ logger.info("Test (step 12): verify MPLS LIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ['rt1', 'rt2', 'rt3', 'rt4', 'rt5', 'rt6']:
+ router_compare_json_output(rname, "show mpls table json",
+ "step1/show_mpls_table.ref")
+
+# Memory leak test template
+def test_memory_leak():
+ "Run the memory leak test and report results."
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip('Memory leak test/report is disabled')
+
+ tgen.report_memory_leaks()
+
+if __name__ == '__main__':
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py
index 87765e4db5..69c807f300 100644
--- a/tests/topotests/lib/bgp.py
+++ b/tests/topotests/lib/bgp.py
@@ -22,8 +22,9 @@ from copy import deepcopy
from time import sleep
import traceback
import ipaddr
+import os
+import sys
from lib import topotest
-
from lib.topolog import logger
# Import common_config to use commomnly used APIs
@@ -36,13 +37,15 @@ from lib.common_config import (
validate_ip_address,
find_interface_with_greater_ip,
run_frr_cmd,
+ FRRCFG_FILE,
retry,
)
-BGP_CONVERGENCE_TIMEOUT = 10
+LOGDIR = "/tmp/topotests/"
+TMPDIR = None
-def create_router_bgp(tgen, topo, input_dict=None, build=False):
+def create_router_bgp(tgen, topo, input_dict=None, build=False, load_config=True):
"""
API to configure bgp on router
@@ -60,11 +63,24 @@ def create_router_bgp(tgen, topo, input_dict=None, build=False):
"bgp": {
"local_as": "200",
"router_id": "22.22.22.22",
+ "graceful-restart": {
+ "graceful-restart": True,
+ "preserve-fw-state": True,
+ "timer": {
+ "restart-time": 30,
+ "rib-stale-time": 30,
+ "select-defer-time": 30,
+ }
+ },
"address_family": {
"ipv4": {
"unicast": {
- "redistribute": [
- {"redist_type": "static"},
+ "redistribute": [{
+ "redist_type": "static",
+ "attribute": {
+ "metric" : 123
+ }
+ },
{"redist_type": "connected"}
],
"advertise_networks": [
@@ -84,7 +100,7 @@ def create_router_bgp(tgen, topo, input_dict=None, build=False):
"dest_link": {
"r4": {
"allowas-in": {
- "number_occurences":2
+ "number_occurences": 2
},
"prefix_lists": [
{
@@ -92,12 +108,13 @@ def create_router_bgp(tgen, topo, input_dict=None, build=False):
"direction": "in"
}
],
- "route_maps": [
- {"name": "RMAP_MED_R3",
- "direction": "in"}
- ],
+ "route_maps": [{
+ "name": "RMAP_MED_R3",
+ "direction": "in"
+ }],
"next_hop_self": True
- }
+ },
+ "r1": {"graceful-restart-helper": True}
}
}
}
@@ -113,8 +130,12 @@ def create_router_bgp(tgen, topo, input_dict=None, build=False):
-------
True or False
"""
- logger.debug("Entering lib API: create_router_bgp()")
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
result = False
+
+ # Flag is used when testing ipv6 over ipv4 or vice-versa
+ afi_test = False
+
if not input_dict:
input_dict = deepcopy(topo)
else:
@@ -126,43 +147,53 @@ def create_router_bgp(tgen, topo, input_dict=None, build=False):
logger.debug("Router %s: 'bgp' not present in input_dict", router)
continue
- data_all_bgp = __create_bgp_global(tgen, input_dict, router, build)
- if data_all_bgp:
- bgp_data = input_dict[router]["bgp"]
+ bgp_data_list = input_dict[router]["bgp"]
- bgp_addr_data = bgp_data.setdefault("address_family", {})
+ if type(bgp_data_list) is not list:
+ bgp_data_list = [bgp_data_list]
- if not bgp_addr_data:
- logger.debug(
- "Router %s: 'address_family' not present in " "input_dict for BGP",
- router,
- )
- else:
+ for bgp_data in bgp_data_list:
+ data_all_bgp = __create_bgp_global(tgen, bgp_data, router, build)
+ if data_all_bgp:
+ bgp_addr_data = bgp_data.setdefault("address_family", {})
- ipv4_data = bgp_addr_data.setdefault("ipv4", {})
- ipv6_data = bgp_addr_data.setdefault("ipv6", {})
+ if not bgp_addr_data:
+ logger.debug(
+ "Router %s: 'address_family' not present in "
+ "input_dict for BGP",
+ router,
+ )
+ else:
- neigh_unicast = (
- True
- if ipv4_data.setdefault("unicast", {})
- or ipv6_data.setdefault("unicast", {})
- else False
- )
+ ipv4_data = bgp_addr_data.setdefault("ipv4", {})
+ ipv6_data = bgp_addr_data.setdefault("ipv6", {})
- if neigh_unicast:
- data_all_bgp = __create_bgp_unicast_neighbor(
- tgen, topo, input_dict, router, config_data=data_all_bgp
+ neigh_unicast = (
+ True
+ if ipv4_data.setdefault("unicast", {})
+ or ipv6_data.setdefault("unicast", {})
+ else False
)
- try:
- result = create_common_configuration(
- tgen, router, data_all_bgp, "bgp", build
- )
- except InvalidCLIError:
- # Traceback
- errormsg = traceback.format_exc()
- logger.error(errormsg)
- return errormsg
+ if neigh_unicast:
+ data_all_bgp = __create_bgp_unicast_neighbor(
+ tgen,
+ topo,
+ bgp_data,
+ router,
+ afi_test,
+ config_data=data_all_bgp,
+ )
+
+ try:
+ result = create_common_configuration(
+ tgen, router, data_all_bgp, "bgp", build, load_config
+ )
+ except InvalidCLIError:
+ # Traceback
+ errormsg = traceback.format_exc()
+ logger.error(errormsg)
+ return errormsg
logger.debug("Exiting lib API: create_router_bgp()")
return result
@@ -184,19 +215,16 @@ def __create_bgp_global(tgen, input_dict, router, build=False):
True or False
"""
- logger.debug("Entering lib API: __create_bgp_global()")
+ result = False
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
- bgp_data = input_dict[router]["bgp"]
+ bgp_data = input_dict
del_bgp_action = bgp_data.setdefault("delete", False)
- if del_bgp_action:
- config_data = ["no router bgp"]
-
- return config_data
config_data = []
if "local_as" not in bgp_data and build:
- logger.error(
+ logger.debug(
"Router %s: 'local_as' not present in input_dict" "for BGP", router
)
return False
@@ -207,9 +235,13 @@ def __create_bgp_global(tgen, input_dict, router, build=False):
if vrf_id:
cmd = "{} vrf {}".format(cmd, vrf_id)
- config_data.append(cmd)
+ if del_bgp_action:
+ cmd = "no {}".format(cmd)
+ config_data.append(cmd)
+
+ return config_data
- # Skip RFC8212 in topotests
+ config_data.append(cmd)
config_data.append("no bgp ebgp-requires-policy")
router_id = bgp_data.setdefault("router_id", None)
@@ -220,10 +252,78 @@ def __create_bgp_global(tgen, input_dict, router, build=False):
config_data.append("bgp router-id {}".format(router_id))
config_data.append("no bgp network import-check")
+
+ if "graceful-restart" in bgp_data:
+ graceful_config = bgp_data["graceful-restart"]
+
+ graceful_restart = graceful_config.setdefault("graceful-restart", None)
+
+ graceful_restart_disable = graceful_config.setdefault(
+ "graceful-restart-disable", None
+ )
+
+ preserve_fw_state = graceful_config.setdefault("preserve-fw-state", None)
+
+ disable_eor = graceful_config.setdefault("disable-eor", None)
+
+ if graceful_restart == False:
+ cmd = "no bgp graceful-restart"
+ if graceful_restart:
+ cmd = "bgp graceful-restart"
+
+ if graceful_restart is not None:
+ config_data.append(cmd)
+
+ if graceful_restart_disable == False:
+ cmd = "no bgp graceful-restart-disable"
+ if graceful_restart_disable:
+ cmd = "bgp graceful-restart-disable"
+
+ if graceful_restart_disable is not None:
+ config_data.append(cmd)
+
+ if preserve_fw_state == False:
+ cmd = "no bgp graceful-restart preserve-fw-state"
+ if preserve_fw_state:
+ cmd = "bgp graceful-restart preserve-fw-state"
+
+ if preserve_fw_state is not None:
+ config_data.append(cmd)
+
+ if disable_eor == False:
+ cmd = "no bgp graceful-restart disable-eor"
+ if disable_eor:
+ cmd = "bgp graceful-restart disable-eor"
+
+ if disable_eor is not None:
+ config_data.append(cmd)
+
+ if "timer" in bgp_data["graceful-restart"]:
+ timer = bgp_data["graceful-restart"]["timer"]
+
+ if "delete" in timer:
+ del_action = timer["delete"]
+ else:
+ del_action = False
+
+ for rs_timer, value in timer.items():
+ rs_timer_value = timer.setdefault(rs_timer, None)
+
+ if rs_timer_value and rs_timer != "delete":
+ cmd = "bgp graceful-restart {} {}".format(rs_timer, rs_timer_value)
+
+ if del_action:
+ cmd = "no {}".format(cmd)
+
+ config_data.append(cmd)
+
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
return config_data
-def __create_bgp_unicast_neighbor(tgen, topo, input_dict, router, config_data=None):
+def __create_bgp_unicast_neighbor(
+ tgen, topo, input_dict, router, afi_test, config_data=None
+):
"""
Helper API to create configuration for address-family unicast
@@ -233,21 +333,25 @@ def __create_bgp_unicast_neighbor(tgen, topo, input_dict, router, config_data=No
* `topo` : json file data
* `input_dict` : Input dict data, required when configuring from testcase
* `router` : router id to be configured.
+ * `afi_test` : use when ipv6 needs to be tested over ipv4 or vice-versa
* `build` : Only for initial setup phase this is set as True.
"""
- logger.debug("Entering lib API: __create_bgp_unicast_neighbor()")
+ result = False
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
add_neigh = True
+ bgp_data = input_dict
if "router bgp" in config_data:
add_neigh = False
- bgp_data = input_dict[router]["bgp"]["address_family"]
+
+ bgp_data = input_dict["address_family"]
for addr_type, addr_dict in bgp_data.iteritems():
if not addr_dict:
continue
- if not check_address_types(addr_type):
+ if not check_address_types(addr_type) and not afi_test:
continue
addr_data = addr_dict["unicast"]
@@ -314,14 +418,19 @@ def __create_bgp_unicast_neighbor(tgen, topo, input_dict, router, config_data=No
if redistribute_data:
for redistribute in redistribute_data:
if "redist_type" not in redistribute:
- logger.error(
+ logger.debug(
"Router %s: 'redist_type' not present in " "input_dict", router
)
else:
cmd = "redistribute {}".format(redistribute["redist_type"])
redist_attr = redistribute.setdefault("attribute", None)
if redist_attr:
- cmd = "{} {}".format(cmd, redist_attr)
+ if isinstance(redist_attr, dict):
+ for key, value in redist_attr.items():
+ cmd = "{} {} {}".format(cmd, key, value)
+ else:
+ cmd = "{} {}".format(cmd, redist_attr)
+
del_action = redistribute.setdefault("delete", False)
if del_action:
cmd = "no {}".format(cmd)
@@ -345,7 +454,7 @@ def __create_bgp_unicast_neighbor(tgen, topo, input_dict, router, config_data=No
config_data.extend(neigh_addr_data)
- logger.debug("Exiting lib API: __create_bgp_unicast_neighbor()")
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
return config_data
@@ -362,15 +471,20 @@ def __create_bgp_neighbor(topo, input_dict, router, addr_type, add_neigh=True):
"""
config_data = []
- logger.debug("Entering lib API: __create_bgp_neighbor()")
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
- bgp_data = input_dict[router]["bgp"]["address_family"]
+ bgp_data = input_dict["address_family"]
neigh_data = bgp_data[addr_type]["unicast"]["neighbor"]
for name, peer_dict in neigh_data.iteritems():
for dest_link, peer in peer_dict["dest_link"].iteritems():
nh_details = topo[name]
- remote_as = nh_details["bgp"]["local_as"]
+
+ if "vrfs" in topo[router]:
+ remote_as = nh_details["bgp"][0]["local_as"]
+ else:
+ remote_as = nh_details["bgp"]["local_as"]
+
update_source = None
if dest_link in nh_details["links"].keys():
@@ -392,6 +506,9 @@ def __create_bgp_neighbor(topo, input_dict, router, addr_type, add_neigh=True):
hold_down = peer.setdefault("holddowntimer", 180)
password = peer.setdefault("password", None)
max_hop_limit = peer.setdefault("ebgp_multihop", 1)
+ graceful_restart = peer.setdefault("graceful-restart", None)
+ graceful_restart_helper = peer.setdefault("graceful-restart-helper", None)
+ graceful_restart_disable = peer.setdefault("graceful-restart-disable", None)
if update_source:
config_data.append(
@@ -409,6 +526,22 @@ def __create_bgp_neighbor(topo, input_dict, router, addr_type, add_neigh=True):
config_data.append(
"{} timers {} {}".format(neigh_cxt, keep_alive, hold_down)
)
+
+ if graceful_restart:
+ config_data.append("{} graceful-restart".format(neigh_cxt))
+ elif graceful_restart == False:
+ config_data.append("no {} graceful-restart".format(neigh_cxt))
+
+ if graceful_restart_helper:
+ config_data.append("{} graceful-restart-helper".format(neigh_cxt))
+ elif graceful_restart_helper == False:
+ config_data.append("no {} graceful-restart-helper".format(neigh_cxt))
+
+ if graceful_restart_disable:
+ config_data.append("{} graceful-restart-disable".format(neigh_cxt))
+ elif graceful_restart_disable == False:
+ config_data.append("no {} graceful-restart-disable".format(neigh_cxt))
+
if password:
config_data.append("{} password {}".format(neigh_cxt, password))
@@ -418,7 +551,7 @@ def __create_bgp_neighbor(topo, input_dict, router, addr_type, add_neigh=True):
)
config_data.append("{} enforce-multihop".format(neigh_cxt))
- logger.debug("Exiting lib API: __create_bgp_unicast_neighbor()")
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
return config_data
@@ -439,15 +572,18 @@ def __create_bgp_unicast_address_family(
"""
config_data = []
- logger.debug("Entering lib API: __create_bgp_unicast_neighbor()")
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
- bgp_data = input_dict[router]["bgp"]["address_family"]
+ bgp_data = input_dict["address_family"]
neigh_data = bgp_data[addr_type]["unicast"]["neighbor"]
for peer_name, peer_dict in deepcopy(neigh_data).iteritems():
for dest_link, peer in peer_dict["dest_link"].iteritems():
deactivate = None
+ activate = None
nh_details = topo[peer_name]
+ activate_addr_family = peer.setdefault("activate", None)
+ deactivate_addr_family = peer.setdefault("deactivate", None)
# Loopback interface
if "source_link" in peer and peer["source_link"] == "lo":
for destRouterLink, data in sorted(nh_details["links"].iteritems()):
@@ -469,9 +605,23 @@ def __create_bgp_unicast_address_family(
neigh_cxt = "neighbor {}".format(ip_addr)
config_data.append("address-family {} unicast".format(addr_type))
- if deactivate:
+
+ if activate_addr_family is not None:
+ config_data.append(
+ "address-family {} unicast".format(activate_addr_family)
+ )
+
+ config_data.append("{} activate".format(neigh_cxt))
+
+ if deactivate and activate_addr_family is None:
config_data.append("no neighbor {} activate".format(deactivate))
+ if deactivate_addr_family is not None:
+ config_data.append(
+ "address-family {} unicast".format(deactivate_addr_family)
+ )
+ config_data.append("no {} activate".format(neigh_cxt))
+
next_hop_self = peer.setdefault("next_hop_self", None)
send_community = peer.setdefault("send_community", None)
prefix_lists = peer.setdefault("prefix_lists", {})
@@ -480,8 +630,12 @@ def __create_bgp_unicast_address_family(
allowas_in = peer.setdefault("allowas-in", None)
# next-hop-self
- if next_hop_self:
- config_data.append("{} next-hop-self".format(neigh_cxt))
+ if next_hop_self is not None:
+ if next_hop_self is True:
+ config_data.append("{} next-hop-self".format(neigh_cxt))
+ else:
+ config_data.append("no {} next-hop-self".format(neigh_cxt))
+
# send_community
if send_community:
config_data.append("{} send-community".format(neigh_cxt))
@@ -547,6 +701,100 @@ def __create_bgp_unicast_address_family(
return config_data
+def modify_bgp_config_when_bgpd_down(tgen, topo, input_dict):
+ """
+ API will save the current config to router's /etc/frr/ for BGPd
+ daemon(bgpd.conf file)
+
+ Paramters
+ ---------
+ * `tgen` : Topogen object
+ * `topo` : json file data
+ * `input_dict` : defines for which router, and which config
+ needs to be modified
+
+ Usage:
+ ------
+ # Modify graceful-restart config not to set f-bit
+ # and write to /etc/frr
+
+ # Api call to delete advertised networks
+ input_dict_2 = {
+ "r5": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": "101.0.20.1/32",
+ "no_of_network": 5,
+ "delete": True
+ }
+ ],
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "advertise_networks": [
+ {
+ "network": "5::1/128",
+ "no_of_network": 5,
+ "delete": True
+ }
+ ],
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = modify_bgp_config_when_bgpd_down(tgen, topo, input_dict)
+
+ """
+
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+ try:
+
+ global LOGDIR
+
+ result = create_router_bgp(
+ tgen, topo, input_dict, build=False, load_config=False
+ )
+ if result is not True:
+ return result
+
+ # Copy bgp config file to /etc/frr
+ for dut in input_dict.keys():
+ router_list = tgen.routers()
+ for router, rnode in router_list.iteritems():
+ if router != dut:
+ continue
+
+ TMPDIR = os.path.join(LOGDIR, tgen.modname)
+
+ logger.info("Delete BGP config when BGPd is down in {}".format(router))
+ # Reading the config from /tmp/topotests and
+ # copy to /etc/frr/bgpd.conf
+ cmd = "cat {}/{}/{} >> /etc/frr/bgpd.conf".format(
+ TMPDIR, router, FRRCFG_FILE
+ )
+ router_list[router].run(cmd)
+
+ except Exception as e:
+ # handle any exception
+ logger.error("Error %s occured. Arguments %s.", e.message, e.args)
+
+ # Traceback
+ errormsg = traceback.format_exc()
+ logger.error(errormsg)
+ return errormsg
+
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+ return True
+
+
#############################################
# Verification APIs
#############################################
@@ -585,7 +833,7 @@ def verify_router_id(tgen, topo, input_dict):
errormsg(str) or True
"""
- logger.debug("Entering lib API: verify_router_id()")
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
for router in input_dict.keys():
if router not in tgen.routers():
continue
@@ -616,26 +864,29 @@ def verify_router_id(tgen, topo, input_dict):
)
return errormsg
- logger.debug("Exiting lib API: verify_router_id()")
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
return True
@retry(attempts=20, wait=2, return_is_str=True)
-def verify_bgp_convergence(tgen, topo):
+def verify_bgp_convergence(tgen, topo, dut=None):
"""
API will verify if BGP is converged with in the given time frame.
Running "show bgp summary json" command and verify bgp neighbor
state is established,
+
Parameters
----------
* `tgen`: topogen object
* `topo`: input json file data
- * `addr_type`: ip_type, ipv4/ipv6
+ * `dut`: device under test
+
Usage
-----
# To veriry is BGP is converged for all the routers used in
topology
- results = verify_bgp_convergence(tgen, topo, "ipv4")
+ results = verify_bgp_convergence(tgen, topo, dut="r1")
+
Returns
-------
errormsg(str) or True
@@ -646,52 +897,260 @@ def verify_bgp_convergence(tgen, topo):
if "bgp" not in topo["routers"][router]:
continue
- logger.info("Verifying BGP Convergence on router %s", router)
- show_bgp_json = run_frr_cmd(rnode, "show bgp summary json", isjson=True)
+ if dut is not None and dut != router:
+ continue
+
+ logger.info("Verifying BGP Convergence on router %s:", router)
+ show_bgp_json = run_frr_cmd(rnode, "show bgp vrf all summary json", isjson=True)
# Verifying output dictionary show_bgp_json is empty or not
if not bool(show_bgp_json):
errormsg = "BGP is not running"
return errormsg
# To find neighbor ip type
- bgp_addr_type = topo["routers"][router]["bgp"]["address_family"]
- for addr_type in bgp_addr_type.keys():
- if not check_address_types(addr_type):
- continue
- total_peer = 0
+ bgp_data_list = topo["routers"][router]["bgp"]
- bgp_neighbors = bgp_addr_type[addr_type]["unicast"]["neighbor"]
+ if type(bgp_data_list) is not list:
+ bgp_data_list = [bgp_data_list]
- for bgp_neighbor in bgp_neighbors:
- total_peer += len(bgp_neighbors[bgp_neighbor]["dest_link"])
+ for bgp_data in bgp_data_list:
+ if "vrf" in bgp_data:
+ vrf = bgp_data["vrf"]
+ if vrf is None:
+ vrf = "default"
+ else:
+ vrf = "default"
+
+ # To find neighbor ip type
+ bgp_addr_type = bgp_data["address_family"]
+ if "l2vpn" in bgp_addr_type:
+ total_evpn_peer = 0
+
+ if "neighbor" not in bgp_addr_type["l2vpn"]["evpn"]:
+ continue
+
+ bgp_neighbors = bgp_addr_type["l2vpn"]["evpn"]["neighbor"]
+ total_evpn_peer += len(bgp_neighbors)
+
+ no_of_evpn_peer = 0
+ for bgp_neighbor, peer_data in bgp_neighbors.items():
+ for _addr_type, dest_link_dict in peer_data.items():
+ data = topo["routers"][bgp_neighbor]["links"]
+ for dest_link in dest_link_dict.keys():
+ if dest_link in data:
+ peer_details = peer_data[_addr_type][dest_link]
+
+ neighbor_ip = data[dest_link][_addr_type].split("/")[0]
+ nh_state = None
+
+ if (
+ "ipv4Unicast" in show_bgp_json[vrf]
+ or "ipv6Unicast" in show_bgp_json[vrf]
+ ):
+ errormsg = (
+ "[DUT: %s] VRF: %s, "
+ "ipv4Unicast/ipv6Unicast"
+ " address-family present"
+ " under l2vpn" % (router, vrf)
+ )
+ return errormsg
- for addr_type in bgp_addr_type.keys():
- if not check_address_types(addr_type):
- continue
- bgp_neighbors = bgp_addr_type[addr_type]["unicast"]["neighbor"]
+ l2VpnEvpn_data = show_bgp_json[vrf]["l2VpnEvpn"][
+ "peers"
+ ]
+ nh_state = l2VpnEvpn_data[neighbor_ip]["state"]
- no_of_peer = 0
- for bgp_neighbor, peer_data in bgp_neighbors.iteritems():
- for dest_link in peer_data["dest_link"].keys():
- data = topo["routers"][bgp_neighbor]["links"]
- if dest_link in data:
- neighbor_ip = data[dest_link][addr_type].split("/")[0]
- if addr_type == "ipv4":
- ipv4_data = show_bgp_json["ipv4Unicast"]["peers"]
- nh_state = ipv4_data[neighbor_ip]["state"]
- else:
- ipv6_data = show_bgp_json["ipv6Unicast"]["peers"]
- nh_state = ipv6_data[neighbor_ip]["state"]
+ if nh_state == "Established":
+ no_of_evpn_peer += 1
- if nh_state == "Established":
- no_of_peer += 1
- if no_of_peer == total_peer:
- logger.info("BGP is Converged for router %s", router)
+ if no_of_evpn_peer == total_evpn_peer:
+ logger.info(
+ "[DUT: %s] VRF: %s, BGP is Converged for " "epvn peers",
+ router,
+ vrf,
+ )
+ else:
+ errormsg = (
+ "[DUT: %s] VRF: %s, BGP is not converged "
+ "for evpn peers" % (router, vrf)
+ )
+ return errormsg
+ else:
+ for addr_type in bgp_addr_type.keys():
+ if not check_address_types(addr_type):
+ continue
+ total_peer = 0
+
+ bgp_neighbors = bgp_addr_type[addr_type]["unicast"]["neighbor"]
+
+ for bgp_neighbor in bgp_neighbors:
+ total_peer += len(bgp_neighbors[bgp_neighbor]["dest_link"])
+
+ for addr_type in bgp_addr_type.keys():
+ if not check_address_types(addr_type):
+ continue
+ bgp_neighbors = bgp_addr_type[addr_type]["unicast"]["neighbor"]
+
+ no_of_peer = 0
+ for bgp_neighbor, peer_data in bgp_neighbors.items():
+ for dest_link in peer_data["dest_link"].keys():
+ data = topo["routers"][bgp_neighbor]["links"]
+ if dest_link in data:
+ peer_details = peer_data["dest_link"][dest_link]
+ # for link local neighbors
+ if (
+ "neighbor_type" in peer_details
+ and peer_details["neighbor_type"] == "link-local"
+ ):
+ neighbor_ip = get_ipv6_linklocal_address(
+ topo["routers"], bgp_neighbor, dest_link
+ )
+ elif "source_link" in peer_details:
+ neighbor_ip = topo["routers"][bgp_neighbor][
+ "links"
+ ][peer_details["source_link"]][addr_type].split(
+ "/"
+ )[
+ 0
+ ]
+ elif (
+ "neighbor_type" in peer_details
+ and peer_details["neighbor_type"] == "unnumbered"
+ ):
+ neighbor_ip = data[dest_link]["peer-interface"]
+ else:
+ neighbor_ip = data[dest_link][addr_type].split("/")[
+ 0
+ ]
+ nh_state = None
+
+ if addr_type == "ipv4":
+ ipv4_data = show_bgp_json[vrf]["ipv4Unicast"][
+ "peers"
+ ]
+ nh_state = ipv4_data[neighbor_ip]["state"]
+ else:
+ ipv6_data = show_bgp_json[vrf]["ipv6Unicast"][
+ "peers"
+ ]
+ nh_state = ipv6_data[neighbor_ip]["state"]
+
+ if nh_state == "Established":
+ no_of_peer += 1
+
+ if no_of_peer == total_peer:
+ logger.info("[DUT: %s] VRF: %s, BGP is Converged", router, vrf)
+ else:
+ errormsg = "[DUT: %s] VRF: %s, BGP is not converged" % (router, vrf)
+ return errormsg
+
+ logger.debug("Exiting API: verify_bgp_convergence()")
+ return True
+
+
+@retry(attempts=3, wait=4, return_is_str=True)
+def verify_bgp_community(
+ tgen, addr_type, router, network, input_dict=None, vrf=None, bestpath=False
+):
+ """
+ API to veiryf BGP large community is attached in route for any given
+ DUT by running "show bgp ipv4/6 {route address} json" command.
+
+ Parameters
+ ----------
+ * `tgen`: topogen object
+ * `addr_type` : ip type, ipv4/ipv6
+ * `dut`: Device Under Test
+ * `network`: network for which set criteria needs to be verified
+ * `input_dict`: having details like - for which router, community and
+ values needs to be verified
+ * `vrf`: VRF name
+ * `bestpath`: To check best path cli
+
+ Usage
+ -----
+ networks = ["200.50.2.0/32"]
+ input_dict = {
+ "largeCommunity": "2:1:1 2:2:2 2:3:3 2:4:4 2:5:5"
+ }
+ result = verify_bgp_community(tgen, "ipv4", dut, network, input_dict=None)
+
+ Returns
+ -------
+ errormsg(str) or True
+ """
+
+ logger.debug("Entering lib API: verify_bgp_community()")
+ if router not in tgen.routers():
+ return False
+
+ rnode = tgen.routers()[router]
+
+ logger.info(
+ "Verifying BGP community attributes on dut %s: for %s " "network %s",
+ router,
+ addr_type,
+ network,
+ )
+
+ command = "show bgp"
+
+ sleep(5)
+ for net in network:
+ if vrf:
+ cmd = "{} vrf {} {} {} json".format(command, vrf, addr_type, net)
+ elif bestpath:
+ cmd = "{} {} {} bestpath json".format(command, addr_type, net)
else:
- errormsg = "BGP is not converged for router {}".format(router)
+ cmd = "{} {} {} json".format(command, addr_type, net)
+
+ show_bgp_json = run_frr_cmd(rnode, cmd, isjson=True)
+ if "paths" not in show_bgp_json:
+ return "Prefix {} not found in BGP table of router: {}".format(net, router)
+
+ as_paths = show_bgp_json["paths"]
+ found = False
+ for i in range(len(as_paths)):
+ if (
+ "largeCommunity" in show_bgp_json["paths"][i]
+ or "community" in show_bgp_json["paths"][i]
+ ):
+ found = True
+ logger.info(
+ "Large Community attribute is found for route:" " %s in router: %s",
+ net,
+ router,
+ )
+ if input_dict is not None:
+ for criteria, comm_val in input_dict.items():
+ show_val = show_bgp_json["paths"][i][criteria]["string"]
+ if comm_val == show_val:
+ logger.info(
+ "Verifying BGP %s for prefix: %s"
+ " in router: %s, found expected"
+ " value: %s",
+ criteria,
+ net,
+ router,
+ comm_val,
+ )
+ else:
+ errormsg = (
+ "Failed: Verifying BGP attribute"
+ " {} for route: {} in router: {}"
+ ", expected value: {} but found"
+ ": {}".format(criteria, net, router, comm_val, show_val)
+ )
+ return errormsg
+
+ if not found:
+ errormsg = (
+ "Large Community attribute is not found for route: "
+ "{} in router: {} ".format(net, router)
+ )
return errormsg
- logger.debug("Exiting API: verify_bgp_convergence()")
+ logger.debug("Exiting lib API: verify_bgp_community()")
return True
@@ -723,7 +1182,7 @@ def modify_as_number(tgen, topo, input_dict):
errormsg(str) or True
"""
- logger.debug("Entering lib API: modify_as_number()")
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
try:
new_topo = deepcopy(topo["routers"])
@@ -750,8 +1209,7 @@ def modify_as_number(tgen, topo, input_dict):
logger.error(errormsg)
return errormsg
- logger.debug("Exiting lib API: modify_as_number()")
-
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
return True
@@ -785,7 +1243,7 @@ def verify_as_numbers(tgen, topo, input_dict):
errormsg(str) or True
"""
- logger.debug("Entering lib API: verify_as_numbers()")
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
for router in input_dict.keys():
if router not in tgen.routers():
continue
@@ -850,10 +1308,60 @@ def verify_as_numbers(tgen, topo, input_dict):
remote_as,
)
- logger.debug("Exiting lib API: verify_AS_numbers()")
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
return True
+def clear_bgp(tgen, addr_type, router, vrf=None):
+ """
+ This API is to clear bgp neighborship by running
+ clear ip bgp */clear bgp ipv6 * command,
+
+ Parameters
+ ----------
+ * `tgen`: topogen object
+ * `addr_type`: ip type ipv4/ipv6
+ * `router`: device under test
+ * `vrf`: vrf name
+
+ Usage
+ -----
+ clear_bgp(tgen, addr_type, "r1")
+ """
+
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+ if router not in tgen.routers():
+ return False
+
+ rnode = tgen.routers()[router]
+
+ if vrf:
+ if type(vrf) is not list:
+ vrf = [vrf]
+
+ # Clearing BGP
+ logger.info("Clearing BGP neighborship for router %s..", router)
+ if addr_type == "ipv4":
+ if vrf:
+ for _vrf in vrf:
+ run_frr_cmd(rnode, "clear ip bgp vrf {} *".format(_vrf))
+ else:
+ run_frr_cmd(rnode, "clear ip bgp *")
+ elif addr_type == "ipv6":
+ if vrf:
+ for _vrf in vrf:
+ run_frr_cmd(rnode, "clear bgp vrf {} ipv6 *".format(_vrf))
+ else:
+ run_frr_cmd(rnode, "clear bgp ipv6 *")
+ else:
+ run_frr_cmd(rnode, "clear bgp *")
+
+ sleep(5)
+
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+
+
def clear_bgp_and_verify(tgen, topo, router):
"""
This API is to clear bgp neighborship and verify bgp neighborship
@@ -877,7 +1385,7 @@ def clear_bgp_and_verify(tgen, topo, router):
errormsg(str) or True
"""
- logger.debug("Entering lib API: clear_bgp_and_verify()")
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
if router not in tgen.routers():
return False
@@ -1048,7 +1556,7 @@ def clear_bgp_and_verify(tgen, topo, router):
)
return errormsg
- logger.debug("Exiting lib API: clear_bgp_and_verify()")
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
return True
@@ -1084,7 +1592,7 @@ def verify_bgp_timers_and_functionality(tgen, topo, input_dict):
errormsg(str) or True
"""
- logger.debug("Entering lib API: verify_bgp_timers_and_functionality()")
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
sleep(5)
router_list = tgen.routers()
for router in input_dict.keys():
@@ -1291,7 +1799,7 @@ def verify_bgp_timers_and_functionality(tgen, topo, input_dict):
bgp_neighbor,
)
- logger.debug("Exiting lib API: verify_bgp_timers_and_functionality()")
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
return True
@@ -1355,7 +1863,7 @@ def verify_bgp_attributes(
errormsg(str) or True
"""
- logger.debug("Entering lib API: verify_bgp_attributes()")
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
for router, rnode in tgen.routers().iteritems():
if router != dut:
continue
@@ -1430,7 +1938,7 @@ def verify_bgp_attributes(
)
return errormsg
- logger.debug("Exiting lib API: verify_bgp_attributes()")
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
return True
@@ -1443,7 +1951,6 @@ def verify_best_path_as_per_bgp_attribute(
"show bgp ipv4/6 json" command will be run and verify best path according
to shortest as-path, highest local-preference and med, lowest weight and
route origin IGP>EGP>INCOMPLETE.
-
Parameters
----------
* `tgen` : topogen object
@@ -1452,7 +1959,6 @@ def verify_best_path_as_per_bgp_attribute(
* `attribute` : calculate best path using this attribute
* `input_dict`: defines different routes to calculate for which route
best path is selected
-
Usage
-----
# To verify best path for routes 200.50.2.0/32 and 200.60.2.0/32 from
@@ -1485,117 +1991,158 @@ def verify_best_path_as_per_bgp_attribute(
errormsg(str) or True
"""
- logger.debug("Entering lib API: verify_best_path_as_per_bgp_attribute()")
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
if router not in tgen.routers():
return False
rnode = tgen.routers()[router]
- command = "show bgp {} json".format(addr_type)
+ # Verifying show bgp json
+ command = "show bgp"
- sleep(5)
+ sleep(2)
logger.info("Verifying router %s RIB for best path:", router)
- sh_ip_bgp_json = run_frr_cmd(rnode, command, isjson=True)
+ static_route = False
+ advertise_network = False
for route_val in input_dict.values():
- net_data = route_val["bgp"]["address_family"][addr_type]["unicast"]
- networks = net_data["advertise_networks"]
- for network in networks:
- route = network["network"]
+ if "static_routes" in route_val:
+ static_route = True
+ networks = route_val["static_routes"]
+ else:
+ advertise_network = True
+ net_data = route_val["bgp"]["address_family"][addr_type]["unicast"]
+ networks = net_data["advertise_networks"]
- route_attributes = sh_ip_bgp_json["routes"][route]
- _next_hop = None
- compare = None
- attribute_dict = {}
- for route_attribute in route_attributes:
- next_hops = route_attribute["nexthops"]
- for next_hop in next_hops:
- next_hop_ip = next_hop["ip"]
- attribute_dict[next_hop_ip] = route_attribute[attribute]
+ for network in networks:
+ _network = network["network"]
+ no_of_ip = network.setdefault("no_of_ip", 1)
+ vrf = network.setdefault("vrf", None)
- # AS_PATH attribute
- if attribute == "path":
- # Find next_hop for the route have minimum as_path
- _next_hop = min(
- attribute_dict, key=lambda x: len(set(attribute_dict[x]))
- )
- compare = "SHORTEST"
-
- # LOCAL_PREF attribute
- elif attribute == "locPrf":
- # Find next_hop for the route have highest local preference
- _next_hop = max(attribute_dict, key=(lambda k: attribute_dict[k]))
- compare = "HIGHEST"
-
- # WEIGHT attribute
- elif attribute == "weight":
- # Find next_hop for the route have highest weight
- _next_hop = max(attribute_dict, key=(lambda k: attribute_dict[k]))
- compare = "HIGHEST"
-
- # ORIGIN attribute
- elif attribute == "origin":
- # Find next_hop for the route have IGP as origin, -
- # - rule is IGP>EGP>INCOMPLETE
- _next_hop = [
- key for (key, value) in attribute_dict.iteritems() if value == "IGP"
- ][0]
- compare = ""
-
- # MED attribute
- elif attribute == "metric":
- # Find next_hop for the route have LOWEST MED
- _next_hop = min(attribute_dict, key=(lambda k: attribute_dict[k]))
- compare = "LOWEST"
-
- # Show ip route
- if addr_type == "ipv4":
- command = "show ip route json"
+ if vrf:
+ cmd = "{} vrf {}".format(command, vrf)
else:
- command = "show ipv6 route json"
+ cmd = command
+
+ cmd = "{} {}".format(cmd, addr_type)
+ cmd = "{} json".format(cmd)
+ sh_ip_bgp_json = run_frr_cmd(rnode, cmd, isjson=True)
+
+ routes = generate_ips(_network, no_of_ip)
+ for route in routes:
+ route = str(ipaddr.IPNetwork(unicode(route)))
+
+ if route in sh_ip_bgp_json["routes"]:
+ route_attributes = sh_ip_bgp_json["routes"][route]
+ _next_hop = None
+ compare = None
+ attribute_dict = {}
+ for route_attribute in route_attributes:
+ next_hops = route_attribute["nexthops"]
+ for next_hop in next_hops:
+ next_hop_ip = next_hop["ip"]
+ attribute_dict[next_hop_ip] = route_attribute[attribute]
+
+ # AS_PATH attribute
+ if attribute == "path":
+ # Find next_hop for the route have minimum as_path
+ _next_hop = min(
+ attribute_dict, key=lambda x: len(set(attribute_dict[x]))
+ )
+ compare = "SHORTEST"
- rib_routes_json = run_frr_cmd(rnode, command, isjson=True)
+ # LOCAL_PREF attribute
+ elif attribute == "locPrf":
+ # Find next_hop for the route have highest local preference
+ _next_hop = max(
+ attribute_dict, key=(lambda k: attribute_dict[k])
+ )
+ compare = "HIGHEST"
- # Verifying output dictionary rib_routes_json is not empty
- if not bool(rib_routes_json):
- errormsg = "No route found in RIB of router {}..".format(router)
- return errormsg
+ # WEIGHT attribute
+ elif attribute == "weight":
+ # Find next_hop for the route have highest weight
+ _next_hop = max(
+ attribute_dict, key=(lambda k: attribute_dict[k])
+ )
+ compare = "HIGHEST"
+
+ # ORIGIN attribute
+ elif attribute == "origin":
+ # Find next_hop for the route have IGP as origin, -
+ # - rule is IGP>EGP>INCOMPLETE
+ _next_hop = [
+ key
+ for (key, value) in attribute_dict.iteritems()
+ if value == "IGP"
+ ][0]
+ compare = ""
+
+ # MED attribute
+ elif attribute == "metric":
+ # Find next_hop for the route have LOWEST MED
+ _next_hop = min(
+ attribute_dict, key=(lambda k: attribute_dict[k])
+ )
+ compare = "LOWEST"
- st_found = False
- nh_found = False
- # Find best is installed in RIB
- if route in rib_routes_json:
- st_found = True
- # Verify next_hop in rib_routes_json
- if rib_routes_json[route][0]["nexthops"][0]["ip"] in attribute_dict:
- nh_found = True
- else:
- errormsg = (
- "Incorrect Nexthop for BGP route {} in "
- "RIB of router {}, Expected: {}, Found:"
- " {}\n".format(
+ # Show ip route
+ if addr_type == "ipv4":
+ command_1 = "show ip route"
+ else:
+ command_1 = "show ipv6 route"
+
+ if vrf:
+ cmd = "{} vrf {} json".format(command_1, vrf)
+ else:
+ cmd = "{} json".format(command_1)
+
+ rib_routes_json = run_frr_cmd(rnode, cmd, isjson=True)
+
+ # Verifying output dictionary rib_routes_json is not empty
+ if not bool(rib_routes_json):
+ errormsg = "No route found in RIB of router {}..".format(router)
+ return errormsg
+
+ st_found = False
+ nh_found = False
+ # Find best is installed in RIB
+ if route in rib_routes_json:
+ st_found = True
+ # Verify next_hop in rib_routes_json
+ if (
+ rib_routes_json[route][0]["nexthops"][0]["ip"]
+ in attribute_dict
+ ):
+ nh_found = True
+ else:
+ errormsg = (
+ "Incorrect Nexthop for BGP route {} in "
+ "RIB of router {}, Expected: {}, Found:"
+ " {}\n".format(
+ route,
+ router,
+ rib_routes_json[route][0]["nexthops"][0]["ip"],
+ _next_hop,
+ )
+ )
+ return errormsg
+
+ if st_found and nh_found:
+ logger.info(
+ "Best path for prefix: %s with next_hop: %s is "
+ "installed according to %s %s: (%s) in RIB of "
+ "router %s",
route,
- router,
- rib_routes_json[route][0]["nexthops"][0]["ip"],
_next_hop,
+ compare,
+ attribute,
+ attribute_dict[_next_hop],
+ router,
)
- )
- return errormsg
-
- if st_found and nh_found:
- logger.info(
- "Best path for prefix: %s with next_hop: %s is "
- "installed according to %s %s: (%s) in RIB of "
- "router %s",
- route,
- _next_hop,
- compare,
- attribute,
- attribute_dict[_next_hop],
- router,
- )
- logger.debug("Exiting lib API: verify_best_path_as_per_bgp_attribute()")
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
return True
@@ -1634,7 +2181,7 @@ def verify_best_path_as_per_admin_distance(
errormsg(str) or True
"""
- logger.debug("Entering lib API: verify_best_path_as_per_admin_distance()")
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
router_list = tgen.routers()
if router not in router_list:
return False
@@ -1706,7 +2253,7 @@ def verify_best_path_as_per_admin_distance(
router,
)
- logger.info("Exiting lib API: verify_best_path_as_per_admin_distance()")
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
return True
@@ -1959,250 +2506,887 @@ def verify_bgp_rib(tgen, addr_type, dut, input_dict, next_hop=None, aspath=None)
return True
-@retry(attempts=5, wait=2, return_is_str=True, initial_wait=2)
-def verify_bgp_rib(tgen, addr_type, dut, input_dict, next_hop=None, aspath=None):
+@retry(attempts=4, wait=2, return_is_str=True, initial_wait=2)
+def verify_graceful_restart(tgen, topo, addr_type, input_dict, dut, peer):
"""
- This API is to verify whether bgp rib has any
- matching route for a nexthop.
+ This API is to verify verify_graceful_restart configuration of DUT and
+ cross verify the same from the peer bgp routerrouter.
Parameters
----------
* `tgen`: topogen object
- * `dut`: input dut router name
+ * `topo`: input json file data
* `addr_type` : ip type ipv4/ipv6
- * `input_dict` : input dict, has details of static routes
- * `next_hop`[optional]: next_hop which needs to be verified,
- default = static
- * 'aspath'[optional]: aspath which needs to be verified
+ * `input_dict`: input dictionary, have details of Device Under Test, for
+ which user wants to test the data
+ * `dut`: input dut router name
+ * `peer`: input peer router name
Usage
-----
- dut = 'r1'
- next_hop = "192.168.1.10"
- input_dict = topo['routers']
- aspath = "100 200 300"
- result = verify_bgp_rib(tgen, addr_type, dut, tgen, input_dict,
- next_hop, aspath)
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link":{
+ "r1": {
+ "graceful-restart": True
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link":{
+ "r1": {
+ "graceful-restart": True
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = verify_graceful_restart(tgen, topo, addr_type, input_dict,
+ dut = "r1", peer = 'r2')
Returns
-------
errormsg(str) or True
"""
- logger.debug("Entering lib API: verify_bgp_rib()")
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
- router_list = tgen.routers()
- additional_nexthops_in_required_nhs = []
- list1 = []
- list2 = []
- for routerInput in input_dict.keys():
- for router, rnode in router_list.iteritems():
- if router != dut:
+ for router, rnode in tgen.routers().iteritems():
+ if router != dut:
+ continue
+
+ bgp_addr_type = topo["routers"][dut]["bgp"]["address_family"]
+
+ if addr_type in bgp_addr_type:
+ if not check_address_types(addr_type):
continue
- # Verifying RIB routes
- command = "show bgp"
+ bgp_neighbors = bgp_addr_type[addr_type]["unicast"]["neighbor"]
- # Static routes
- sleep(2)
- logger.info("Checking router {} BGP RIB:".format(dut))
+ for bgp_neighbor, peer_data in bgp_neighbors.items():
+ if bgp_neighbor != peer:
+ continue
- if "static_routes" in input_dict[routerInput]:
- static_routes = input_dict[routerInput]["static_routes"]
+ for dest_link, peer_dict in peer_data["dest_link"].items():
+ data = topo["routers"][bgp_neighbor]["links"]
- for static_route in static_routes:
- found_routes = []
- missing_routes = []
- st_found = False
- nh_found = False
- vrf = static_route.setdefault("vrf", None)
- if vrf:
- cmd = "{} vrf {} {}".format(command, vrf, addr_type)
+ if dest_link in data:
+ neighbor_ip = data[dest_link][addr_type].split("/")[0]
- else:
- cmd = "{} {}".format(command, addr_type)
+ logger.info(
+ "[DUT: {}]: Checking bgp graceful-restart show"
+ " o/p {}".format(dut, neighbor_ip)
+ )
- cmd = "{} json".format(cmd)
+ show_bgp_graceful_json = None
- rib_routes_json = run_frr_cmd(rnode, cmd, isjson=True)
+ show_bgp_graceful_json = run_frr_cmd(
+ rnode,
+ "show bgp {} neighbor {} graceful-restart json".format(
+ addr_type, neighbor_ip
+ ),
+ isjson=True,
+ )
- # Verifying output dictionary rib_routes_json is not empty
- if bool(rib_routes_json) == False:
- errormsg = "No route found in rib of router {}..".format(router)
- return errormsg
+ show_bgp_graceful_json_out = show_bgp_graceful_json[neighbor_ip]
- network = static_route["network"]
+ if show_bgp_graceful_json_out["neighborAddr"] == neighbor_ip:
+ logger.info(
+ "[DUT: {}]: Neighbor ip matched {}".format(dut, neighbor_ip)
+ )
+ else:
+ errormsg = "[DUT: {}]: Neighbor ip NOT a matched {}".format(
+ dut, neighbor_ip
+ )
+ return errormsg
- if "no_of_ip" in static_route:
- no_of_ip = static_route["no_of_ip"]
+ lmode = None
+ rmode = None
+ # Local GR mode
+ if "address_family" in input_dict[dut]["bgp"]:
+ bgp_neighbors = input_dict[dut]["bgp"]["address_family"][addr_type][
+ "unicast"
+ ]["neighbor"][peer]["dest_link"]
+
+ for dest_link, data in bgp_neighbors.items():
+ if (
+ "graceful-restart-helper" in data
+ and data["graceful-restart-helper"]
+ ):
+ lmode = "Helper"
+ elif "graceful-restart" in data and data["graceful-restart"]:
+ lmode = "Restart"
+ elif (
+ "graceful-restart-disable" in data
+ and data["graceful-restart-disable"]
+ ):
+ lmode = "Disable"
else:
- no_of_ip = 1
+ lmode = None
- # Generating IPs for verification
- ip_list = generate_ips(network, no_of_ip)
+ if lmode is None:
+ if "graceful-restart" in input_dict[dut]["bgp"]:
- for st_rt in ip_list:
- st_rt = str(ipaddr.IPNetwork(unicode(st_rt)))
+ if (
+ "graceful-restart" in input_dict[dut]["bgp"]["graceful-restart"]
+ and input_dict[dut]["bgp"]["graceful-restart"][
+ "graceful-restart"
+ ]
+ ):
+ lmode = "Restart*"
+ elif (
+ "graceful-restart-disable"
+ in input_dict[dut]["bgp"]["graceful-restart"]
+ and input_dict[dut]["bgp"]["graceful-restart"][
+ "graceful-restart-disable"
+ ]
+ ):
+ lmode = "Disable*"
+ else:
+ lmode = "Helper*"
+ else:
+ lmode = "Helper*"
+
+ if lmode == "Disable" or lmode == "Disable*":
+ return True
+
+ # Remote GR mode
+ if "address_family" in input_dict[peer]["bgp"]:
+ bgp_neighbors = input_dict[peer]["bgp"]["address_family"][addr_type][
+ "unicast"
+ ]["neighbor"][dut]["dest_link"]
+
+ for dest_link, data in bgp_neighbors.items():
+ if (
+ "graceful-restart-helper" in data
+ and data["graceful-restart-helper"]
+ ):
+ rmode = "Helper"
+ elif "graceful-restart" in data and data["graceful-restart"]:
+ rmode = "Restart"
+ elif (
+ "graceful-restart-disable" in data
+ and data["graceful-restart-disable"]
+ ):
+ rmode = "Disable"
+ else:
+ rmode = None
- _addr_type = validate_ip_address(st_rt)
- if _addr_type != addr_type:
- continue
+ if rmode is None:
+ if "graceful-restart" in input_dict[peer]["bgp"]:
- if st_rt in rib_routes_json["routes"]:
- st_found = True
- found_routes.append(st_rt)
+ if (
+ "graceful-restart"
+ in input_dict[peer]["bgp"]["graceful-restart"]
+ and input_dict[peer]["bgp"]["graceful-restart"][
+ "graceful-restart"
+ ]
+ ):
+ rmode = "Restart"
+ elif (
+ "graceful-restart-disable"
+ in input_dict[peer]["bgp"]["graceful-restart"]
+ and input_dict[peer]["bgp"]["graceful-restart"][
+ "graceful-restart-disable"
+ ]
+ ):
+ rmode = "Disable"
+ else:
+ rmode = "Helper"
+ else:
+ rmode = "Helper"
- if next_hop:
- 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][
- "nexthops"
- ]
- ]
- list2 = found_hops
- missing_list_of_nexthops = set(list2).difference(list1)
- additional_nexthops_in_required_nhs = set(
- list1
- ).difference(list2)
+ if show_bgp_graceful_json_out["localGrMode"] == lmode:
+ logger.info(
+ "[DUT: {}]: localGrMode : {} ".format(
+ dut, show_bgp_graceful_json_out["localGrMode"]
+ )
+ )
+ else:
+ errormsg = (
+ "[DUT: {}]: localGrMode is not correct"
+ " Expected: {}, Found: {}".format(
+ dut, lmode, show_bgp_graceful_json_out["localGrMode"]
+ )
+ )
+ return errormsg
- if list2:
- if additional_nexthops_in_required_nhs:
- logger.info(
- "Missing nexthop %s for route"
- " %s in RIB of router %s\n",
- additional_nexthops_in_required_nhs,
- st_rt,
- dut,
- )
- errormsg = (
- "Nexthop {} is Missing for "
- "route {} in RIB of router {}\n".format(
- additional_nexthops_in_required_nhs,
- st_rt,
- dut,
- )
- )
- return errormsg
- else:
- nh_found = True
- if aspath:
- found_paths = rib_routes_json["routes"][st_rt][0][
- "path"
- ]
- if aspath == found_paths:
- aspath_found = True
- logger.info(
- "Found AS path {} for route"
- " {} in RIB of router "
- "{}\n".format(aspath, st_rt, dut)
- )
- else:
- errormsg = (
- "AS Path {} is missing for route"
- "for route {} in RIB of router {}\n".format(
- aspath, st_rt, dut
- )
- )
- return errormsg
+ if show_bgp_graceful_json_out["remoteGrMode"] == rmode:
+ logger.info(
+ "[DUT: {}]: remoteGrMode : {} ".format(
+ dut, show_bgp_graceful_json_out["remoteGrMode"]
+ )
+ )
+ elif (
+ show_bgp_graceful_json_out["remoteGrMode"] == "NotApplicable"
+ and rmode == "Disable"
+ ):
+ logger.info(
+ "[DUT: {}]: remoteGrMode : {} ".format(
+ dut, show_bgp_graceful_json_out["remoteGrMode"]
+ )
+ )
+ else:
+ errormsg = (
+ "[DUT: {}]: remoteGrMode is not correct"
+ " Expected: {}, Found: {}".format(
+ dut, rmode, show_bgp_graceful_json_out["remoteGrMode"]
+ )
+ )
+ return errormsg
- else:
- missing_routes.append(st_rt)
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+ return True
- if nh_found:
- logger.info(
- "Found next_hop {} for all bgp"
- " routes in RIB of"
- " router {}\n".format(next_hop, router)
- )
- if len(missing_routes) > 0:
- errormsg = (
- "Missing route in RIB of router {}, "
- "routes: {}\n".format(dut, missing_routes)
- )
- return errormsg
+@retry(attempts=4, wait=2, return_is_str=True, initial_wait=2)
+def verify_r_bit(tgen, topo, addr_type, input_dict, dut, peer):
+ """
+ This API is to verify r_bit in the BGP gr capability advertised
+ by the neighbor router
- if found_routes:
- logger.info(
- "Verified routes in router {} BGP RIB, "
- "found routes are: {} \n".format(dut, found_routes)
- )
- continue
+ Parameters
+ ----------
+ * `tgen`: topogen object
+ * `topo`: input json file data
+ * `addr_type` : ip type ipv4/ipv6
+ * `input_dict`: input dictionary, have details of Device Under Test, for
+ which user wants to test the data
+ * `dut`: input dut router name
+ * `peer`: peer name
+ Usage
+ -----
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link":{
+ "r1": {
+ "graceful-restart": True
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link":{
+ "r1": {
+ "graceful-restart": True
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = verify_r_bit(tgen, topo, addr_type, input_dict, dut, peer)
- if "bgp" not in input_dict[routerInput]:
+ Returns
+ -------
+ errormsg(str) or True
+ """
+
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+ for router, rnode in tgen.routers().iteritems():
+ if router != dut:
+ continue
+
+ bgp_addr_type = topo["routers"][router]["bgp"]["address_family"]
+
+ if addr_type in bgp_addr_type:
+ if not check_address_types(addr_type):
continue
- # Advertise networks
- bgp_data_list = input_dict[routerInput]["bgp"]
+ bgp_neighbors = bgp_addr_type[addr_type]["unicast"]["neighbor"]
- if type(bgp_data_list) is not list:
- bgp_data_list = [bgp_data_list]
+ for bgp_neighbor, peer_data in bgp_neighbors.items():
+ if bgp_neighbor != peer:
+ continue
- for bgp_data in bgp_data_list:
- vrf_id = bgp_data.setdefault("vrf", None)
- if vrf_id:
- cmd = "{} vrf {} {}".format(command, vrf_id, addr_type)
+ for dest_link, peer_dict in peer_data["dest_link"].items():
+ data = topo["routers"][bgp_neighbor]["links"]
+
+ if dest_link in data:
+ neighbor_ip = data[dest_link][addr_type].split("/")[0]
+
+ logger.info(
+ "[DUT: {}]: Checking bgp graceful-restart show"
+ " o/p {}".format(dut, neighbor_ip)
+ )
+
+ show_bgp_graceful_json = run_frr_cmd(
+ rnode,
+ "show bgp {} neighbor {} graceful-restart json".format(
+ addr_type, neighbor_ip
+ ),
+ isjson=True,
+ )
+
+ show_bgp_graceful_json_out = show_bgp_graceful_json[neighbor_ip]
+
+ if show_bgp_graceful_json_out["neighborAddr"] == neighbor_ip:
+ logger.info(
+ "[DUT: {}]: Neighbor ip matched {}".format(dut, neighbor_ip)
+ )
+ else:
+ errormsg = "[DUT: {}]: Neighbor ip NOT a matched {}".format(
+ dut, neighbor_ip
+ )
+ return errormsg
+
+ if "rBit" in show_bgp_graceful_json_out:
+ if show_bgp_graceful_json_out["rBit"]:
+ logger.info("[DUT: {}]: Rbit true {}".format(dut, neighbor_ip))
else:
- cmd = "{} {}".format(command, addr_type)
+ errormsg = "[DUT: {}]: Rbit false {}".format(dut, neighbor_ip)
+ return errormsg
- cmd = "{} json".format(cmd)
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+ return True
- rib_routes_json = run_frr_cmd(rnode, cmd, isjson=True)
- # Verifying output dictionary rib_routes_json is not empty
- if bool(rib_routes_json) == False:
- errormsg = "No route found in rib of router {}..".format(router)
+@retry(attempts=4, wait=2, return_is_str=True, initial_wait=2)
+def verify_eor(tgen, topo, addr_type, input_dict, dut, peer):
+ """
+ This API is to verify EOR
+
+ Parameters
+ ----------
+ * `tgen`: topogen object
+ * `topo`: input json file data
+ * `addr_type` : ip type ipv4/ipv6
+ * `input_dict`: input dictionary, have details of DUT, for
+ which user wants to test the data
+ * `dut`: input dut router name
+ * `peer`: peer name
+ Usage
+ -----
+ input_dict = {
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link":{
+ "r1": {
+ "graceful-restart": True
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link":{
+ "r1": {
+ "graceful-restart": True
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = verify_eor(tgen, topo, addr_type, input_dict, dut, peer)
+
+ Returns
+ -------
+ errormsg(str) or True
+ """
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+ for router, rnode in tgen.routers().iteritems():
+ if router != dut:
+ continue
+
+ bgp_addr_type = topo["routers"][router]["bgp"]["address_family"]
+
+ if addr_type in bgp_addr_type:
+ if not check_address_types(addr_type):
+ continue
+
+ bgp_neighbors = bgp_addr_type[addr_type]["unicast"]["neighbor"]
+
+ for bgp_neighbor, peer_data in bgp_neighbors.items():
+ if bgp_neighbor != peer:
+ continue
+
+ for dest_link, peer_dict in peer_data["dest_link"].items():
+ data = topo["routers"][bgp_neighbor]["links"]
+
+ if dest_link in data:
+ neighbor_ip = data[dest_link][addr_type].split("/")[0]
+
+ logger.info(
+ "[DUT: %s]: Checking bgp graceful-restart" " show o/p %s",
+ dut,
+ neighbor_ip,
+ )
+
+ show_bgp_graceful_json = run_frr_cmd(
+ rnode,
+ "show bgp {} neighbor {} graceful-restart json".format(
+ addr_type, neighbor_ip
+ ),
+ isjson=True,
+ )
+
+ show_bgp_graceful_json_out = show_bgp_graceful_json[neighbor_ip]
+
+ if show_bgp_graceful_json_out["neighborAddr"] == neighbor_ip:
+ logger.info("[DUT: %s]: Neighbor ip matched %s", dut, neighbor_ip)
+ else:
+ errormsg = "[DUT: %s]: Neighbor ip is NOT matched %s" % (
+ dut,
+ neighbor_ip,
+ )
+ return errormsg
+
+ if addr_type == "ipv4":
+ afi = "ipv4Unicast"
+ elif addr_type == "ipv6":
+ afi = "ipv6Unicast"
+ else:
+ errormsg = "Address type %s is not supported" % (addr_type)
+ return errormsg
+
+ eor_json = show_bgp_graceful_json_out[afi]["endOfRibStatus"]
+ if "endOfRibSend" in eor_json:
+
+ if eor_json["endOfRibSend"]:
+ logger.info(
+ "[DUT: %s]: EOR Send true for %s " "%s", dut, neighbor_ip, afi
+ )
+ else:
+ errormsg = "[DUT: %s]: EOR Send false for %s" " %s" % (
+ dut,
+ neighbor_ip,
+ afi,
+ )
return errormsg
- bgp_net_advertise = bgp_data["address_family"][addr_type]["unicast"]
- advertise_network = bgp_net_advertise.setdefault(
- "advertise_networks", []
+ if "endOfRibRecv" in eor_json:
+ if eor_json["endOfRibRecv"]:
+ logger.info(
+ "[DUT: %s]: EOR Recv true %s " "%s", dut, neighbor_ip, afi
+ )
+ else:
+ errormsg = "[DUT: %s]: EOR Recv false %s " "%s" % (
+ dut,
+ neighbor_ip,
+ afi,
+ )
+ return errormsg
+
+ if "endOfRibSentAfterUpdate" in eor_json:
+ if eor_json["endOfRibSentAfterUpdate"]:
+ logger.info(
+ "[DUT: %s]: EOR SendTime true for %s" " %s",
+ dut,
+ neighbor_ip,
+ afi,
+ )
+ else:
+ errormsg = "[DUT: %s]: EOR SendTime false for " "%s %s" % (
+ dut,
+ neighbor_ip,
+ afi,
+ )
+ return errormsg
+
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+ return True
+
+
+@retry(attempts=4, wait=2, return_is_str=True, initial_wait=2)
+def verify_f_bit(tgen, topo, addr_type, input_dict, dut, peer):
+ """
+ This API is to verify f_bit in the BGP gr capability advertised
+ by the neighbor router
+
+ Parameters
+ ----------
+ * `tgen`: topogen object
+ * `topo`: input json file data
+ * `addr_type` : ip type ipv4/ipv6
+ * `input_dict`: input dictionary, have details of Device Under Test, for
+ which user wants to test the data
+ * `dut`: input dut router name
+ * `peer`: peer name
+
+ Usage
+ -----
+ input_dict = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link":{
+ "r1": {
+ "graceful-restart": True
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link":{
+ "r1": {
+ "graceful-restart": True
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = verify_f_bit(tgen, topo, 'ipv4', input_dict, dut, peer)
+
+ Returns
+ -------
+ errormsg(str) or True
+ """
+
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+ for router, rnode in tgen.routers().iteritems():
+ if router != dut:
+ continue
+
+ bgp_addr_type = topo["routers"][router]["bgp"]["address_family"]
+
+ if addr_type in bgp_addr_type:
+ if not check_address_types(addr_type):
+ continue
+
+ bgp_neighbors = bgp_addr_type[addr_type]["unicast"]["neighbor"]
+
+ for bgp_neighbor, peer_data in bgp_neighbors.items():
+ if bgp_neighbor != peer:
+ continue
+
+ for dest_link, peer_dict in peer_data["dest_link"].items():
+ data = topo["routers"][bgp_neighbor]["links"]
+
+ if dest_link in data:
+ neighbor_ip = data[dest_link][addr_type].split("/")[0]
+
+ logger.info(
+ "[DUT: {}]: Checking bgp graceful-restart show"
+ " o/p {}".format(dut, neighbor_ip)
+ )
+
+ show_bgp_graceful_json = run_frr_cmd(
+ rnode,
+ "show bgp {} neighbor {} graceful-restart json".format(
+ addr_type, neighbor_ip
+ ),
+ isjson=True,
+ )
+
+ show_bgp_graceful_json_out = show_bgp_graceful_json[neighbor_ip]
+
+ if show_bgp_graceful_json_out["neighborAddr"] == neighbor_ip:
+ logger.info(
+ "[DUT: {}]: Neighbor ip matched {}".format(dut, neighbor_ip)
)
+ else:
+ errormsg = "[DUT: {}]: Neighbor ip NOT a match {}".format(
+ dut, neighbor_ip
+ )
+ return errormsg
- for advertise_network_dict in advertise_network:
- found_routes = []
- missing_routes = []
- found = False
+ if "ipv4Unicast" in show_bgp_graceful_json_out:
+ if show_bgp_graceful_json_out["ipv4Unicast"]["fBit"]:
+ logger.info(
+ "[DUT: {}]: Fbit True for {} IPv4"
+ " Unicast".format(dut, neighbor_ip)
+ )
+ else:
+ errormsg = "[DUT: {}]: Fbit False for {} IPv4" " Unicast".format(
+ dut, neighbor_ip
+ )
+ return errormsg
- network = advertise_network_dict["network"]
+ elif "ipv6Unicast" in show_bgp_graceful_json_out:
+ if show_bgp_graceful_json_out["ipv6Unicast"]["fBit"]:
+ logger.info(
+ "[DUT: {}]: Fbit True for {} IPv6"
+ " Unicast".format(dut, neighbor_ip)
+ )
+ else:
+ errormsg = "[DUT: {}]: Fbit False for {} IPv6" " Unicast".format(
+ dut, neighbor_ip
+ )
+ return errormsg
+ else:
+ show_bgp_graceful_json_out["ipv4Unicast"]
+ show_bgp_graceful_json_out["ipv6Unicast"]
- if "no_of_network" in advertise_network_dict:
- no_of_network = advertise_network_dict["no_of_network"]
- else:
- no_of_network = 1
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+ return True
- # Generating IPs for verification
- ip_list = generate_ips(network, no_of_network)
- for st_rt in ip_list:
- st_rt = str(ipaddr.IPNetwork(unicode(st_rt)))
+@retry(attempts=4, wait=2, return_is_str=True, initial_wait=2)
+def verify_graceful_restart_timers(tgen, topo, addr_type, input_dict, dut, peer):
+ """
+ This API is to verify graceful restart timers, configured and recieved
- _addr_type = validate_ip_address(st_rt)
- if _addr_type != addr_type:
- continue
+ Parameters
+ ----------
+ * `tgen`: topogen object
+ * `topo`: input json file data
+ * `addr_type` : ip type ipv4/ipv6
+ * `input_dict`: input dictionary, have details of Device Under Test,
+ for which user wants to test the data
+ * `dut`: input dut router name
+ * `peer`: peer name
+ Usage
+ -----
+ # Configure graceful-restart
+ input_dict_1 = {
+ "r1": {
+ "bgp": {
+ "bgp_neighbors": {
+ "r3": {
+ "graceful-restart": "graceful-restart-helper"
+ }
+ },
+ "gracefulrestart": ["restart-time 150"]
+ }
+ },
+ "r3": {
+ "bgp": {
+ "bgp_neighbors": {
+ "r1": {
+ "graceful-restart": "graceful-restart"
+ }
+ }
+ }
+ }
+ }
- if st_rt in rib_routes_json["routes"]:
- found = True
- found_routes.append(st_rt)
- else:
- found = False
- missing_routes.append(st_rt)
+ result = verify_graceful_restart_timers(tgen, topo, 'ipv4', input_dict)
- if len(missing_routes) > 0:
- errormsg = (
- "Missing route in BGP RIB of router {},"
- " are: {}\n".format(dut, missing_routes)
- )
- return errormsg
+ Returns
+ -------
+ errormsg(str) or True
+ """
- if found_routes:
- logger.info(
- "Verified routes in router {} BGP RIB, found "
- "routes are: {}\n".format(dut, found_routes)
- )
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
- logger.debug("Exiting lib API: verify_bgp_rib()")
+ for router, rnode in tgen.routers().iteritems():
+ if router != dut:
+ continue
+
+ bgp_addr_type = topo["routers"][dut]["bgp"]["address_family"]
+
+ if addr_type in bgp_addr_type:
+ if not check_address_types(addr_type):
+ continue
+
+ bgp_neighbors = bgp_addr_type[addr_type]["unicast"]["neighbor"]
+
+ for bgp_neighbor, peer_data in bgp_neighbors.items():
+ if bgp_neighbor != peer:
+ continue
+
+ for dest_link, peer_dict in peer_data["dest_link"].items():
+ data = topo["routers"][bgp_neighbor]["links"]
+
+ if dest_link in data:
+ neighbor_ip = data[dest_link][addr_type].split("/")[0]
+
+ logger.info(
+ "[DUT: {}]: Checking bgp graceful-restart show"
+ " o/p {}".format(dut, neighbor_ip)
+ )
+
+ show_bgp_graceful_json = run_frr_cmd(
+ rnode,
+ "show bgp {} neighbor {} graceful-restart json".format(
+ addr_type, neighbor_ip
+ ),
+ isjson=True,
+ )
+
+ show_bgp_graceful_json_out = show_bgp_graceful_json[neighbor_ip]
+ if show_bgp_graceful_json_out["neighborAddr"] == neighbor_ip:
+ logger.info(
+ "[DUT: {}]: Neighbor ip matched {}".format(dut, neighbor_ip)
+ )
+ else:
+ errormsg = "[DUT: {}]: Neighbor ip is NOT matched {}".format(
+ dut, neighbor_ip
+ )
+ return errormsg
+
+ # Graceful-restart timer
+ if "graceful-restart" in input_dict[peer]["bgp"]:
+ if "timer" in input_dict[peer]["bgp"]["graceful-restart"]:
+ for rs_timer, value in input_dict[peer]["bgp"]["graceful-restart"][
+ "timer"
+ ].items():
+ if rs_timer == "restart-time":
+
+ receivedTimer = value
+ if (
+ show_bgp_graceful_json_out["timers"][
+ "receivedRestartTimer"
+ ]
+ == receivedTimer
+ ):
+ logger.info(
+ "receivedRestartTimer is {}"
+ " on {} from peer {}".format(
+ receivedTimer, router, peer
+ )
+ )
+ else:
+ errormsg = (
+ "receivedRestartTimer is not"
+ " as expected {}".format(receivedTimer)
+ )
+ return errormsg
+
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
return True
+
+
+@retry(attempts=4, wait=2, return_is_str=True, initial_wait=2)
+def verify_gr_address_family(tgen, topo, addr_type, addr_family, dut):
+ """
+ This API is to verify gr_address_family in the BGP gr capability advertised
+ by the neighbor router
+
+ Parameters
+ ----------
+ * `tgen`: topogen object
+ * `topo`: input json file data
+ * `addr_type` : ip type ipv4/ipv6
+ * `addr_type` : ip type IPV4 Unicast/IPV6 Unicast
+ * `dut`: input dut router name
+
+ Usage
+ -----
+
+ result = verify_gr_address_family(tgen, topo, "ipv4", "ipv4Unicast", "r1")
+
+ Returns
+ -------
+ errormsg(str) or True
+ """
+
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+ for router, rnode in tgen.routers().iteritems():
+ if router != dut:
+ continue
+
+ bgp_addr_type = topo["routers"][router]["bgp"]["address_family"]
+
+ if addr_type in bgp_addr_type:
+ if not check_address_types(addr_type):
+ continue
+
+ bgp_neighbors = bgp_addr_type[addr_type]["unicast"]["neighbor"]
+
+ for bgp_neighbor, peer_data in bgp_neighbors.items():
+ for dest_link, peer_dict in peer_data["dest_link"].items():
+ data = topo["routers"][bgp_neighbor]["links"]
+
+ if dest_link in data:
+ neighbor_ip = data[dest_link][addr_type].split("/")[0]
+
+ logger.info(
+ "[DUT: {}]: Checking bgp graceful-restart"
+ " show o/p {}".format(dut, neighbor_ip)
+ )
+
+ show_bgp_graceful_json = run_frr_cmd(
+ rnode,
+ "show bgp {} neighbor {} graceful-restart json".format(
+ addr_type, neighbor_ip
+ ),
+ isjson=True,
+ )
+
+ show_bgp_graceful_json_out = show_bgp_graceful_json[neighbor_ip]
+
+ if show_bgp_graceful_json_out["neighborAddr"] == neighbor_ip:
+ logger.info("Neighbor ip matched {}".format(neighbor_ip))
+ else:
+ errormsg = "Neighbor ip NOT a match {}".format(neighbor_ip)
+ return errormsg
+
+ if addr_family == "ipv4Unicast":
+ if "ipv4Unicast" in show_bgp_graceful_json_out:
+ logger.info("ipv4Unicast present for {} ".format(neighbor_ip))
+ return True
+ else:
+ errormsg = "ipv4Unicast NOT present for {} ".format(neighbor_ip)
+ return errormsg
+
+ elif addr_family == "ipv6Unicast":
+ if "ipv6Unicast" in show_bgp_graceful_json_out:
+ logger.info("ipv6Unicast present for {} ".format(neighbor_ip))
+ return True
+ else:
+ errormsg = "ipv6Unicast NOT present for {} ".format(neighbor_ip)
+ return errormsg
+ else:
+ errormsg = "Aaddress family: {} present for {} ".format(
+ addr_family, neighbor_ip
+ )
+ return errormsg
+
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py
index 5ee59070cc..3de7ab3ebe 100644
--- a/tests/topotests/lib/common_config.py
+++ b/tests/topotests/lib/common_config.py
@@ -32,6 +32,7 @@ from tempfile import mkdtemp
import StringIO
import os
+import sys
import ConfigParser
import traceback
import socket
@@ -100,13 +101,11 @@ SEQ_ID = {"prefix_lists": {}, "route_maps": {}}
def get_seq_id(obj_type, router, obj_name):
"""
Generates and saves sequence number in interval of 10
-
Parameters
----------
* `obj_type`: prefix_lists or route_maps
* `router`: router name
*` obj_name`: name of the prefix-list or route-map
-
Returns
--------
Sequence number generated
@@ -125,7 +124,6 @@ def get_seq_id(obj_type, router, obj_name):
def set_seq_id(obj_type, router, id, obj_name):
"""
Saves sequence number if not auto-generated and given by user
-
Parameters
----------
* `obj_type`: prefix_lists or route_maps
@@ -149,11 +147,9 @@ class InvalidCLIError(Exception):
def run_frr_cmd(rnode, cmd, isjson=False):
"""
Execute frr show commands in priviledged mode
-
* `rnode`: router node on which commands needs to executed
* `cmd`: Command to be executed on frr
* `isjson`: If command is to get json data or not
-
:return str:
"""
@@ -179,12 +175,56 @@ def run_frr_cmd(rnode, cmd, isjson=False):
raise InvalidCLIError("No actual cmd passed")
-def create_common_configuration(tgen, router, data, config_type=None, build=False):
+def apply_raw_config(tgen, input_dict):
+
+ """
+ API to configure raw configuration on device. This can be used for any cli
+ which does has not been implemented in JSON.
+
+ Parameters
+ ----------
+ * `tgen`: tgen onject
+ * `input_dict`: configuration that needs to be applied
+
+ Usage
+ -----
+ input_dict = {
+ "r2": {
+ "raw_config": [
+ "router bgp",
+ "no bgp update-group-split-horizon"
+ ]
+ }
+ }
+ Returns
+ -------
+ True or errormsg
+ """
+
+ result = True
+ for router_name in input_dict.keys():
+ config_cmd = input_dict[router_name]["raw_config"]
+
+ if not isinstance(config_cmd, list):
+ config_cmd = [config_cmd]
+
+ frr_cfg_file = "{}/{}/{}".format(TMPDIR, router_name, FRRCFG_FILE)
+ with open(frr_cfg_file, "w") as cfg:
+ for cmd in config_cmd:
+ cfg.write("{}\n".format(cmd))
+
+ result = load_config_to_router(tgen, router_name)
+
+ return result
+
+
+def create_common_configuration(
+ tgen, router, data, config_type=None, build=False, load_config=True
+):
"""
API to create object of class FRRConfig and also create frr_json.conf
file. It will create interface and common configurations and save it to
frr_json.conf and load to router
-
Parameters
----------
* `tgen`: tgen onject
@@ -193,7 +233,6 @@ def create_common_configuration(tgen, router, data, config_type=None, build=Fals
* `config_type` : Syntactic information while writing configuration. Should
be one of the value as mentioned in the config_map below.
* `build` : Only for initial setup phase this is set as True
-
Returns
-------
True or False
@@ -211,11 +250,14 @@ def create_common_configuration(tgen, router, data, config_type=None, build=Fals
"bgp_community_list": "! Community List Config\n",
"route_maps": "! Route Maps Config\n",
"bgp": "! BGP Config\n",
+ "vrf": "! VRF Config\n",
}
)
if build:
mode = "a"
+ elif not load_config:
+ mode = "a"
else:
mode = "w"
@@ -236,12 +278,123 @@ def create_common_configuration(tgen, router, data, config_type=None, build=Fals
frr_cfg_fd.close()
# If configuration applied from build, it will done at last
- if not build:
+ if not build and load_config:
load_config_to_router(tgen, router)
return True
+def kill_router_daemons(tgen, router, daemons):
+ """
+ Router's current config would be saved to /etc/frr/ for each deamon
+ and deamon would be killed forcefully using SIGKILL.
+ * `tgen` : topogen object
+ * `router`: Device under test
+ * `daemons`: list of daemons to be killed
+ """
+
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+ try:
+ router_list = tgen.routers()
+
+ # Saving router config to /etc/frr, which will be loaded to router
+ # when it starts
+ router_list[router].vtysh_cmd("write memory")
+
+ # Kill Daemons
+ result = router_list[router].killDaemons(daemons)
+ if len(result) > 0:
+ assert "Errors found post shutdown - details follow:" == 0, result
+ return result
+
+ except Exception as e:
+ errormsg = traceback.format_exc()
+ logger.error(errormsg)
+ return errormsg
+
+
+def start_router_daemons(tgen, router, daemons):
+ """
+ Daemons defined by user would be started
+ * `tgen` : topogen object
+ * `router`: Device under test
+ * `daemons`: list of daemons to be killed
+ """
+
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+ try:
+ router_list = tgen.routers()
+
+ # Start daemons
+ result = router_list[router].startDaemons(daemons)
+ return result
+
+ except Exception as e:
+ errormsg = traceback.format_exc()
+ logger.error(errormsg)
+ return errormsg
+
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+ return True
+
+
+def kill_mininet_routers_process(tgen):
+ """
+ Kill all mininet stale router' processes
+ * `tgen` : topogen object
+ """
+
+ router_list = tgen.routers()
+ for rname, router in router_list.iteritems():
+ daemon_list = [
+ "zebra",
+ "ospfd",
+ "ospf6d",
+ "bgpd",
+ "ripd",
+ "ripngd",
+ "isisd",
+ "pimd",
+ "ldpd",
+ "staticd",
+ ]
+ for daemon in daemon_list:
+ router.run("killall -9 {}".format(daemon))
+
+
+def check_router_status(tgen):
+ """
+ Check if all daemons are running for all routers in topology
+ * `tgen` : topogen object
+ """
+
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+ try:
+ router_list = tgen.routers()
+ for router, rnode in router_list.iteritems():
+
+ result = rnode.check_router_running()
+ if result != "":
+ daemons = []
+ if "bgpd" in result:
+ daemons.append("bgpd")
+ if "zebra" in result:
+ daemons.append("zebra")
+
+ rnode.startDaemons(daemons)
+
+ except Exception as e:
+ errormsg = traceback.format_exc()
+ logger.error(errormsg)
+ return errormsg
+
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+ return True
+
+
def reset_config_on_routers(tgen, routerName=None):
"""
Resets configuration on routers to the snapshot created using input JSON
@@ -262,6 +415,7 @@ def reset_config_on_routers(tgen, routerName=None):
router = router_list[rname]
logger.info("Configuring router %s to initial test configuration", rname)
+
cfg = router.run("vtysh -c 'show running'")
fname = "{}/{}/frr.sav".format(TMPDIR, rname)
dname = "{}/{}/delta.conf".format(TMPDIR, rname)
@@ -279,22 +433,13 @@ def reset_config_on_routers(tgen, routerName=None):
f.write("\n")
f.close()
-
run_cfg_file = "{}/{}/frr.sav".format(TMPDIR, rname)
init_cfg_file = "{}/{}/frr_json_initial.conf".format(TMPDIR, rname)
-
- tempdir = mkdtemp()
- with open(os.path.join(tempdir, "vtysh.conf"), "w") as fd:
- pass
-
- command = "/usr/lib/frr/frr-reload.py --confdir {} --input {} --test {} > {}".format(
- tempdir, run_cfg_file, init_cfg_file, dname
+ command = "/usr/lib/frr/frr-reload.py --input {} --test {} > {}".format(
+ run_cfg_file, init_cfg_file, dname
)
result = call(command, shell=True, stderr=SUB_STDOUT, stdout=SUB_PIPE)
- os.unlink(os.path.join(tempdir, "vtysh.conf"))
- os.rmdir(tempdir)
-
# Assert if command fail
if result > 0:
logger.error("Delta file creation failed. Command executed %s", command)
@@ -351,11 +496,11 @@ def reset_config_on_routers(tgen, routerName=None):
# Router current configuration to log file or console if
# "show_router_config" is defined in "pytest.ini"
if show_router_config:
- logger.info("Configuration on router {} after config reset:".format(rname))
+ logger.info("Configuration on router {} after reset:".format(rname))
logger.info(delta.getvalue())
delta.close()
- logger.debug("Exting API: reset_config_on_routers")
+ logger.debug("Exiting API: reset_config_on_routers")
return True
@@ -374,7 +519,7 @@ def load_config_to_router(tgen, routerName, save_bkup=False):
router_list = tgen.routers()
for rname in ROUTER_LIST:
- if routerName and routerName != rname:
+ if routerName and rname != routerName:
continue
router = router_list[rname]
@@ -397,6 +542,7 @@ def load_config_to_router(tgen, routerName, save_bkup=False):
raise InvalidCLIError("%s" % output)
cfg.truncate(0)
+
except IOError as err:
errormsg = (
"Unable to open config File. error(%s):" " %s",
@@ -407,13 +553,81 @@ def load_config_to_router(tgen, routerName, save_bkup=False):
# Router current configuration to log file or console if
# "show_router_config" is defined in "pytest.ini"
if show_router_config:
+ logger.info("New configuration for router {}:".format(rname))
new_config = router.run("vtysh -c 'show running'")
logger.info(new_config)
- logger.debug("Exting API: load_config_to_router")
+ logger.debug("Exiting API: load_config_to_router")
return True
+def get_frr_ipv6_linklocal(tgen, router, intf=None, vrf=None):
+ """
+ API to get the link local ipv6 address of a perticular interface using
+ FRR command 'show interface'
+
+ * `tgen`: tgen onject
+ * `router` : router for which hightest interface should be
+ calculated
+ * `intf` : interface for which linklocal address needs to be taken
+ * `vrf` : VRF name
+
+ Usage
+ -----
+ linklocal = get_frr_ipv6_linklocal(tgen, router, "intf1", RED_A)
+
+ Returns
+ -------
+ 1) array of interface names to link local ips.
+ """
+
+ router_list = tgen.routers()
+ for rname, rnode in router_list.iteritems():
+ if rname != router:
+ continue
+
+ linklocal = []
+
+ if vrf:
+ cmd = "show interface vrf {}".format(vrf)
+ else:
+ cmd = "show interface"
+
+ ifaces = router_list[router].run('vtysh -c "{}"'.format(cmd))
+
+ # Fix newlines (make them all the same)
+ ifaces = ("\n".join(ifaces.splitlines()) + "\n").splitlines()
+
+ interface = None
+ ll_per_if_count = 0
+ for line in ifaces:
+ # Interface name
+ m = re_search("Interface ([a-zA-Z0-9-]+) is", line)
+ if m:
+ interface = m.group(1).split(" ")[0]
+ ll_per_if_count = 0
+
+ # Interface ip
+ m1 = re_search("inet6 (fe80[:a-fA-F0-9]+[\/0-9]+)", line)
+ if m1:
+ local = m1.group(1)
+ ll_per_if_count += 1
+ if ll_per_if_count > 1:
+ linklocal += [["%s-%s" % (interface, ll_per_if_count), local]]
+ else:
+ linklocal += [[interface, local]]
+
+ if linklocal:
+ if intf:
+ return [_linklocal[1] for _linklocal in linklocal if _linklocal[0] == intf][
+ 0
+ ].split("/")[0]
+ return linklocal
+ else:
+ errormsg = "Link local ip missing on router {}"
+ return errormsg
+
+
def start_topology(tgen):
"""
Starting topology, create tmp files which are loaded to routers
@@ -468,6 +682,55 @@ def start_topology(tgen):
tgen.start_router()
+def stop_router(tgen, router):
+ """
+ Router"s current config would be saved to /etc/frr/ for each deamon
+ and router and its deamons would be stopped.
+
+ * `tgen` : topogen object
+ * `router`: Device under test
+ """
+
+ router_list = tgen.routers()
+
+ # Saving router config to /etc/frr, which will be loaded to router
+ # when it starts
+ router_list[router].vtysh_cmd("write memory")
+
+ # Stop router
+ router_list[router].stop()
+
+
+def start_router(tgen, router):
+ """
+ Router will started and config would be loaded from /etc/frr/ for each
+ deamon
+
+ * `tgen` : topogen object
+ * `router`: Device under test
+ """
+
+ logger.debug("Entering lib API: start_router")
+
+ try:
+ router_list = tgen.routers()
+
+ # Router and its deamons would be started and config would
+ # be loaded to router for each deamon from /etc/frr
+ router_list[router].start()
+
+ # Waiting for router to come up
+ sleep(5)
+
+ except Exception as e:
+ errormsg = traceback.format_exc()
+ logger.error(errormsg)
+ return errormsg
+
+ logger.debug("Exiting lib API: start_router()")
+ return True
+
+
def number_to_row(routerName):
"""
Returns the number for the router.
@@ -491,14 +754,196 @@ def number_to_column(routerName):
#############################################
+def create_vrf_cfg(tgen, topo, input_dict=None, build=False):
+ """
+ Create vrf configuration for created topology. VRF
+ configuration is provided in input json file.
+
+ VRF config is done in Linux Kernel:
+ * Create VRF
+ * Attach interface to VRF
+ * Bring up VRF
+
+ Parameters
+ ----------
+ * `tgen` : Topogen object
+ * `topo` : json file data
+ * `input_dict` : Input dict data, required when configuring
+ from testcase
+ * `build` : Only for initial setup phase this is set as True.
+
+ Usage
+ -----
+ input_dict={
+ "r3": {
+ "links": {
+ "r2-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_A"},
+ "r2-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED_B"},
+ "r2-link3": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_A"},
+ "r2-link4": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE_B"},
+ },
+ "vrfs":[
+ {
+ "name": "RED_A",
+ "id": "1"
+ },
+ {
+ "name": "RED_B",
+ "id": "2"
+ },
+ {
+ "name": "BLUE_A",
+ "id": "3",
+ "delete": True
+ },
+ {
+ "name": "BLUE_B",
+ "id": "4"
+ }
+ ]
+ }
+ }
+ result = create_vrf_cfg(tgen, topo, input_dict)
+
+ Returns
+ -------
+ True or False
+ """
+ result = True
+ if not input_dict:
+ input_dict = deepcopy(topo)
+ else:
+ input_dict = deepcopy(input_dict)
+
+ try:
+ for c_router, c_data in input_dict.iteritems():
+ rnode = tgen.routers()[c_router]
+ if "vrfs" in c_data:
+ for vrf in c_data["vrfs"]:
+ config_data = []
+ del_action = vrf.setdefault("delete", False)
+ name = vrf.setdefault("name", None)
+ table_id = vrf.setdefault("id", None)
+ vni = vrf.setdefault("vni", None)
+ del_vni = vrf.setdefault("no_vni", None)
+
+ if del_action:
+ # Kernel cmd- Add VRF and table
+ cmd = "ip link del {} type vrf table {}".format(
+ vrf["name"], vrf["id"]
+ )
+
+ logger.info("[DUT: %s]: Running kernel cmd [%s]", c_router, cmd)
+ rnode.run(cmd)
+
+ # Kernel cmd - Bring down VRF
+ cmd = "ip link set dev {} down".format(name)
+ logger.info("[DUT: %s]: Running kernel cmd [%s]", c_router, cmd)
+ rnode.run(cmd)
+
+ else:
+ if name and table_id:
+ # Kernel cmd- Add VRF and table
+ cmd = "ip link add {} type vrf table {}".format(
+ name, table_id
+ )
+ logger.info(
+ "[DUT: %s]: Running kernel cmd " "[%s]", c_router, cmd
+ )
+ rnode.run(cmd)
+
+ # Kernel cmd - Bring up VRF
+ cmd = "ip link set dev {} up".format(name)
+ logger.info(
+ "[DUT: %s]: Running kernel " "cmd [%s]", c_router, cmd
+ )
+ rnode.run(cmd)
+
+ if "links" in c_data:
+ for destRouterLink, data in sorted(
+ c_data["links"].iteritems()
+ ):
+ # Loopback interfaces
+ if "type" in data and data["type"] == "loopback":
+ interface_name = destRouterLink
+ else:
+ interface_name = data["interface"]
+
+ if "vrf" in data:
+ vrf_list = data["vrf"]
+
+ if type(vrf_list) is not list:
+ vrf_list = [vrf_list]
+
+ for _vrf in vrf_list:
+ cmd = "ip link set {} master {}".format(
+ interface_name, _vrf
+ )
+
+ logger.info(
+ "[DUT: %s]: Running" " kernel cmd [%s]",
+ c_router,
+ cmd,
+ )
+ rnode.run(cmd)
+
+ result = create_common_configuration(
+ tgen, c_router, config_data, "vrf", build=build
+ )
+
+ except InvalidCLIError:
+ # Traceback
+ errormsg = traceback.format_exc()
+ logger.error(errormsg)
+ return errormsg
+
+ return result
+
+
+def create_interface_in_kernel(
+ tgen, dut, name, ip_addr, vrf=None, netmask=None, create=True
+):
+ """
+ Cretae interfaces in kernel for ipv4/ipv6
+ Config is done in Linux Kernel:
+
+ Parameters
+ ----------
+ * `tgen` : Topogen object
+ * `dut` : Device for which interfaces to be added
+ * `name` : interface name
+ * `ip_addr` : ip address for interface
+ * `vrf` : VRF name, to which interface will be associated
+ * `netmask` : netmask value, default is None
+ * `create`: Create interface in kernel, if created then no need
+ to create
+ """
+
+ rnode = tgen.routers()[dut]
+
+ if create:
+ cmd = "sudo ip link add name {} type dummy".format(name)
+ rnode.run(cmd)
+
+ addr_type = validate_ip_address(ip_addr)
+ if addr_type == "ipv4":
+ cmd = "ifconfig {} {} netmask {}".format(name, ip_addr, netmask)
+ else:
+ cmd = "ifconfig {} inet6 add {}/{}".format(name, ip_addr, netmask)
+
+ rnode.run(cmd)
+
+ if vrf:
+ cmd = "ip link set {} master {}".format(name, vrf)
+ rnode.run(cmd)
+
+
def validate_ip_address(ip_address):
"""
Validates the type of ip address
-
Parameters
----------
* `ip_address`: IPv4/IPv6 address
-
Returns
-------
Type of address as string
@@ -565,7 +1010,6 @@ def generate_ips(network, no_of_ips):
"""
Returns list of IPs.
based on start_ip and no_of_ips
-
* `network` : from here the ip will start generating,
start_ip will be
* `no_of_ips` : these many IPs will be generated
@@ -606,7 +1050,6 @@ def find_interface_with_greater_ip(topo, router, loopback=True, interface=True):
Returns highest interface ip for ipv4/ipv6. If loopback is there then
it will return highest IP from loopback IPs otherwise from physical
interface IPs.
-
* `topo` : json file data
* `router` : router for which hightest interface should be calculated
"""
@@ -654,11 +1097,9 @@ def write_test_footer(tc_name):
def interface_status(tgen, topo, input_dict):
"""
Delete ip route maps from device
-
* `tgen` : Topogen object
* `topo` : json file data
* `input_dict` : for which router, route map has to be deleted
-
Usage
-----
input_dict = {
@@ -671,7 +1112,7 @@ def interface_status(tgen, topo, input_dict):
-------
errormsg(str) or True
"""
- logger.debug("Entering lib API: interface_status()")
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
try:
global frr_cfg
@@ -695,11 +1136,11 @@ def interface_status(tgen, topo, input_dict):
logger.error(errormsg)
return errormsg
- logger.debug("Exiting lib API: interface_status()")
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
return True
-def retry(attempts=3, wait=2, return_is_str=True, initial_wait=0):
+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
@@ -724,15 +1165,20 @@ def retry(attempts=3, wait=2, return_is_str=True, initial_wait=0):
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)
for i in range(1, _attempts + 1):
try:
_expected = kwargs.setdefault("expected", True)
kwargs.pop("expected")
ret = func(*args, **kwargs)
logger.debug("Function returned %s" % ret)
- if return_is_str and isinstance(ret, bool) and _expected:
+ if _return_is_str and isinstance(ret, bool) and _expected:
return ret
- if isinstance(ret, str) 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:
@@ -798,6 +1244,7 @@ def create_interfaces_cfg(tgen, topo, build=False):
True or False
"""
result = False
+ topo = deepcopy(topo)
try:
for c_router, c_data in topo.iteritems():
@@ -808,13 +1255,30 @@ def create_interfaces_cfg(tgen, topo, build=False):
interface_name = destRouterLink
else:
interface_name = data["interface"]
+
interface_data.append("interface {}".format(str(interface_name)))
if "ipv4" in data:
intf_addr = c_data["links"][destRouterLink]["ipv4"]
- interface_data.append("ip address {}".format(intf_addr))
+
+ if "delete" in data and data["delete"]:
+ interface_data.append("no ip address {}".format(intf_addr))
+ else:
+ interface_data.append("ip address {}".format(intf_addr))
if "ipv6" in data:
intf_addr = c_data["links"][destRouterLink]["ipv6"]
- interface_data.append("ipv6 address {}".format(intf_addr))
+
+ if "delete" in data and data["delete"]:
+ interface_data.append("no ipv6 address {}".format(intf_addr))
+ else:
+ interface_data.append("ipv6 address {}".format(intf_addr))
+
+ if "ipv6-link-local" in data:
+ intf_addr = c_data["links"][destRouterLink]["ipv6-link-local"]
+
+ if "delete" in data and data["delete"]:
+ interface_data.append("no ipv6 address {}".format(intf_addr))
+ else:
+ interface_data.append("ipv6 address {}\n".format(intf_addr))
result = create_common_configuration(
tgen, c_router, interface_data, "interface_config", build=build
@@ -847,6 +1311,7 @@ def create_static_routes(tgen, input_dict, build=False):
# admin_distance: admin distance for route/routes.
# next_hop: starting next-hop address
# tag: tag id for static routes
+ # vrf: VRF name in which static routes needs to be created
# delete: True if config to be removed. Default False.
Example:
@@ -858,7 +1323,8 @@ def create_static_routes(tgen, input_dict, build=False):
"no_of_ip": 9,
"admin_distance": 100,
"next_hop": "10.0.0.1",
- "tag": 4001
+ "tag": 4001,
+ "vrf": "RED_A"
"delete": true
}
]
@@ -872,11 +1338,12 @@ def create_static_routes(tgen, input_dict, build=False):
result = False
logger.debug("Entering lib API: create_static_routes()")
input_dict = deepcopy(input_dict)
+
try:
for router in input_dict.keys():
if "static_routes" not in input_dict[router]:
errormsg = "static_routes not present in input_dict"
- logger.debug(errormsg)
+ logger.info(errormsg)
continue
static_routes_list = []
@@ -884,27 +1351,38 @@ def create_static_routes(tgen, input_dict, build=False):
static_routes = input_dict[router]["static_routes"]
for static_route in static_routes:
del_action = static_route.setdefault("delete", False)
- # No of IPs
no_of_ip = static_route.setdefault("no_of_ip", 1)
- admin_distance = static_route.setdefault("admin_distance", None)
- tag = static_route.setdefault("tag", None)
- if "next_hop" not in static_route or "network" not in static_route:
- errormsg = "'next_hop' or 'network' missing in" " input_dict"
- return errormsg
-
- next_hop = static_route["next_hop"]
- network = static_route["network"]
+ network = static_route.setdefault("network", [])
if type(network) is not list:
network = [network]
+ admin_distance = static_route.setdefault("admin_distance", None)
+ tag = static_route.setdefault("tag", None)
+ vrf = static_route.setdefault("vrf", None)
+ interface = static_route.setdefault("interface", None)
+ next_hop = static_route.setdefault("next_hop", None)
+ nexthop_vrf = static_route.setdefault("nexthop_vrf", None)
+
ip_list = generate_ips(network, no_of_ip)
for ip in ip_list:
addr_type = validate_ip_address(ip)
if addr_type == "ipv4":
- cmd = "ip route {} {}".format(ip, next_hop)
+ cmd = "ip route {}".format(ip)
else:
- cmd = "ipv6 route {} {}".format(ip, next_hop)
+ cmd = "ipv6 route {}".format(ip)
+
+ if interface:
+ cmd = "{} {}".format(cmd, interface)
+
+ if next_hop:
+ cmd = "{} {}".format(cmd, next_hop)
+
+ if nexthop_vrf:
+ cmd = "{} nexthop-vrf {}".format(cmd, nexthop_vrf)
+
+ if vrf:
+ cmd = "{} vrf {}".format(cmd, vrf)
if tag:
cmd = "{} tag {}".format(cmd, str(tag))
@@ -935,13 +1413,11 @@ def create_prefix_lists(tgen, input_dict, build=False):
"""
Create ip prefix lists as per the config provided in input
JSON or input_dict
-
Parameters
----------
* `tgen` : Topogen object
* `input_dict` : Input dict data, required when configuring from testcase
* `build` : Only for initial setup phase this is set as True.
-
Usage
-----
# pf_lists_1: name of prefix-list, user defined
@@ -950,7 +1426,6 @@ def create_prefix_lists(tgen, input_dict, build=False):
# action: permit/deny
# le: less than or equal number of bits
# ge: greater than or equal number of bits
-
Example
-------
input_dict = {
@@ -971,13 +1446,12 @@ def create_prefix_lists(tgen, input_dict, build=False):
}
}
}
-
Returns
-------
errormsg or True
"""
- logger.debug("Entering lib API: create_prefix_lists()")
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
result = False
try:
for router in input_dict.keys():
@@ -1036,20 +1510,18 @@ def create_prefix_lists(tgen, input_dict, build=False):
logger.error(errormsg)
return errormsg
- logger.debug("Exiting lib API: create_prefix_lists()")
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
return result
def create_route_maps(tgen, input_dict, build=False):
"""
Create route-map on the devices as per the arguments passed
-
Parameters
----------
* `tgen` : Topogen object
* `input_dict` : Input dict data, required when configuring from testcase
* `build` : Only for initial setup phase this is set as True.
-
Usage
-----
# route_maps: key, value pair for route-map name and its attribute
@@ -1070,7 +1542,6 @@ def create_route_maps(tgen, input_dict, build=False):
# large_community: large community value to be attached
# community_additive: if set to "additive", adds community/large-community
value to the existing values of the network prefix
-
Example:
--------
input_dict = {
@@ -1086,7 +1557,6 @@ def create_route_maps(tgen, input_dict, build=False):
"ipv6": {
"prefix_list": "pf_list_1"
}
-
"large-community-list": {
"id": "community_1",
"exact_match": True
@@ -1119,14 +1589,13 @@ def create_route_maps(tgen, input_dict, build=False):
}
}
}
-
Returns
-------
errormsg(str) or True
"""
result = False
- logger.debug("Entering lib API: create_route_maps()")
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
input_dict = deepcopy(input_dict)
try:
for router in input_dict.keys():
@@ -1289,6 +1758,9 @@ def create_route_maps(tgen, input_dict, build=False):
"large_community_list", {}
)
+ metric = match_data.setdefault("metric", None)
+ source_vrf = match_data.setdefault("source-vrf", None)
+
if ipv4_data:
# fetch prefix list data from rmap
prefix_name = ipv4_data.setdefault("prefix_lists", None)
@@ -1381,6 +1853,14 @@ def create_route_maps(tgen, input_dict, build=False):
cmd = "{} exact-match".format(cmd)
rmap_data.append(cmd)
+ if source_vrf:
+ cmd = "match source-vrf {}".format(source_vrf)
+ rmap_data.append(cmd)
+
+ if metric:
+ cmd = "match metric {}".format(metric)
+ rmap_data.append(cmd)
+
result = create_common_configuration(
tgen, router, rmap_data, "route_maps", build=build
)
@@ -1391,18 +1871,16 @@ def create_route_maps(tgen, input_dict, build=False):
logger.error(errormsg)
return errormsg
- logger.debug("Exiting lib API: create_route_maps()")
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
return result
def delete_route_maps(tgen, input_dict):
"""
Delete ip route maps from device
-
* `tgen` : Topogen object
* `input_dict` : for which router,
route map has to be deleted
-
Usage
-----
# Delete route-map rmap_1 and rmap_2 from router r1
@@ -1412,12 +1890,11 @@ def delete_route_maps(tgen, input_dict):
}
}
result = delete_route_maps("ipv4", input_dict)
-
Returns
-------
errormsg(str) or True
"""
- logger.info("Entering lib API: delete_route_maps()")
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
for router in input_dict.keys():
route_maps = input_dict[router]["route_maps"][:]
@@ -1433,7 +1910,6 @@ def create_bgp_community_lists(tgen, input_dict, build=False):
"""
Create bgp community-list or large-community-list on the devices as per
the arguments passed. Takes list of communities in input.
-
Parameters
----------
* `tgen` : Topogen object
@@ -1459,7 +1935,7 @@ def create_bgp_community_lists(tgen, input_dict, build=False):
"""
result = False
- logger.debug("Entering lib API: create_bgp_community_lists()")
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
input_dict = deepcopy(input_dict)
try:
for router in input_dict.keys():
@@ -1515,30 +1991,26 @@ def create_bgp_community_lists(tgen, input_dict, build=False):
logger.error(errormsg)
return errormsg
- logger.debug("Exiting lib API: create_bgp_community_lists()")
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
return result
def shutdown_bringup_interface(tgen, dut, intf_name, ifaceaction=False):
"""
Shutdown or bringup router's interface "
-
* `tgen` : Topogen object
* `dut` : Device under test
* `intf_name` : Interface name to be shut/no shut
* `ifaceaction` : Action, to shut/no shut interface,
by default is False
-
Usage
-----
dut = "r3"
intf = "r3-r1-eth0"
# Shut down ineterface
shutdown_bringup_interface(tgen, dut, intf, False)
-
# Bring up ineterface
shutdown_bringup_interface(tgen, dut, intf, True)
-
Returns
-------
errormsg(str) or True
@@ -1553,11 +2025,90 @@ def shutdown_bringup_interface(tgen, dut, intf_name, ifaceaction=False):
interface_set_status(router_list[dut], intf_name, ifaceaction)
+def addKernelRoute(
+ tgen, router, intf, group_addr_range, next_hop=None, src=None, del_action=None
+):
+ """
+ Add route to kernel
+
+ Parameters:
+ -----------
+ * `tgen` : Topogen object
+ * `router`: router for which kernal routes needs to be added
+ * `intf`: interface name, for which kernal routes needs to be added
+ * `bindToAddress`: bind to <host>, an interface or multicast
+ address
+
+ returns:
+ --------
+ errormsg or True
+ """
+
+ logger.debug("Entering lib API: addKernelRoute()")
+
+ rnode = tgen.routers()[router]
+
+ if type(group_addr_range) is not list:
+ group_addr_range = [group_addr_range]
+
+ for grp_addr in group_addr_range:
+
+ addr_type = validate_ip_address(grp_addr)
+ if addr_type == "ipv4":
+ if next_hop is not None:
+ cmd = "ip route add {} via {}".format(grp_addr, next_hop)
+ else:
+ cmd = "ip route add {} dev {}".format(grp_addr, intf)
+ if del_action:
+ cmd = "ip route del {}".format(grp_addr)
+ verify_cmd = "ip route"
+ elif addr_type == "ipv6":
+ if intf and src:
+ cmd = "ip -6 route add {} dev {} src {}".format(grp_addr, intf, src)
+ else:
+ cmd = "ip -6 route add {} via {}".format(grp_addr, next_hop)
+ verify_cmd = "ip -6 route"
+ if del_action:
+ cmd = "ip -6 route del {}".format(grp_addr)
+
+ logger.info("[DUT: {}]: Running command: [{}]".format(router, cmd))
+ output = rnode.run(cmd)
+
+ # Verifying if ip route added to kernal
+ result = rnode.run(verify_cmd)
+ logger.debug("{}\n{}".format(verify_cmd, result))
+ if "/" in grp_addr:
+ ip, mask = grp_addr.split("/")
+ if mask == "32" or mask == "128":
+ grp_addr = ip
+
+ if not re_search(r"{}".format(grp_addr), result) and mask is not "0":
+ errormsg = (
+ "[DUT: {}]: Kernal route is not added for group"
+ " address {} Config output: {}".format(router, grp_addr, output)
+ )
+
+ return errormsg
+
+ logger.debug("Exiting lib API: addKernelRoute()")
+ return True
+
+
#############################################
# Verification APIs
#############################################
-@retry(attempts=10, return_is_str=True, initial_wait=2)
-def verify_rib(tgen, addr_type, dut, input_dict, next_hop=None, protocol=None):
+@retry(attempts=5, wait=2, return_is_str=True, initial_wait=2)
+def verify_rib(
+ tgen,
+ addr_type,
+ dut,
+ input_dict,
+ next_hop=None,
+ protocol=None,
+ tag=None,
+ metric=None,
+ fib=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
@@ -1605,43 +2156,54 @@ def verify_rib(tgen, addr_type, dut, input_dict, next_hop=None, protocol=None):
errormsg(str) or True
"""
- logger.debug("Entering lib API: verify_rib()")
+ logger.info("Entering lib API: verify_rib()")
router_list = tgen.routers()
+ additional_nexthops_in_required_nhs = []
+ found_hops = []
for routerInput in input_dict.keys():
for router, rnode in router_list.iteritems():
if router != dut:
continue
+ logger.info("Checking router %s RIB:", router)
+
# Verifying RIB routes
if addr_type == "ipv4":
- if protocol:
- command = "show ip route {} json".format(protocol)
- else:
- command = "show ip route json"
+ command = "show ip route"
else:
- if protocol:
- command = "show ipv6 route {} json".format(protocol)
- else:
- command = "show ipv6 route json"
+ command = "show ipv6 route"
- logger.info("Checking router %s RIB:", router)
- rib_routes_json = run_frr_cmd(rnode, command, 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(
- protocol, router
- )
- return errormsg
+ found_routes = []
+ missing_routes = []
if "static_routes" in input_dict[routerInput]:
static_routes = input_dict[routerInput]["static_routes"]
- st_found = False
- nh_found = False
+
for static_route in static_routes:
- found_routes = []
- missing_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)
+
+ if protocol:
+ cmd = "{} {}".format(cmd, protocol)
+
+ 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 = "No route found in rib of router {}..".format(router)
+ return errormsg
network = static_route["network"]
if "no_of_ip" in static_route:
@@ -1649,138 +2211,267 @@ def verify_rib(tgen, addr_type, dut, input_dict, next_hop=None, protocol=None):
else:
no_of_ip = 1
+ if "tag" in static_route:
+ _tag = static_route["tag"]
+ else:
+ _tag = None
+
# 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(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 fib and next_hop:
if type(next_hop) is not list:
next_hop = [next_hop]
+ for mnh in range(0, len(rib_routes_json[st_rt])):
+ if (
+ "fib"
+ in rib_routes_json[st_rt][mnh]["nexthops"][0]
+ ):
+ found_hops.append(
+ [
+ rib_r["ip"]
+ for rib_r in rib_routes_json[st_rt][
+ mnh
+ ]["nexthops"]
+ ]
+ )
+
+ if found_hops[0]:
+ missing_list_of_nexthops = set(
+ found_hops[0]
+ ).difference(next_hop)
+ additional_nexthops_in_required_nhs = set(
+ next_hop
+ ).difference(found_hops[0])
+
+ if additional_nexthops_in_required_nhs:
+ logger.info(
+ "Nexthop "
+ "%s is not active for route %s in "
+ "RIB of router %s\n",
+ additional_nexthops_in_required_nhs,
+ st_rt,
+ dut,
+ )
+ errormsg = (
+ "Nexthop {} is not active"
+ " for route {} in RIB of router"
+ " {}\n".format(
+ additional_nexthops_in_required_nhs,
+ st_rt,
+ dut,
+ )
+ )
+ return errormsg
+ else:
+ nh_found = True
+
+ elif next_hop and fib is None:
+ if type(next_hop) is not list:
+ next_hop = [next_hop]
found_hops = [
rib_r["ip"]
for rib_r in rib_routes_json[st_rt][0]["nexthops"]
]
- for nh in found_hops:
- nh_found = False
- if nh and nh in next_hop:
- nh_found = True
- else:
+
+ if found_hops:
+ missing_list_of_nexthops = set(
+ found_hops
+ ).difference(next_hop)
+ additional_nexthops_in_required_nhs = set(
+ next_hop
+ ).difference(found_hops)
+
+ if additional_nexthops_in_required_nhs:
+ logger.info(
+ "Missing nexthop %s for route"
+ " %s in RIB of router %s\n",
+ additional_nexthops_in_required_nhs,
+ st_rt,
+ dut,
+ )
errormsg = (
- "Nexthop {} is Missing for {}"
- " route {} in RIB of router"
- " {}\n".format(
- next_hop, protocol, st_rt, dut
+ "Nexthop {} is Missing for "
+ "route {} in RIB of router {}\n".format(
+ additional_nexthops_in_required_nhs,
+ st_rt,
+ dut,
)
)
-
return errormsg
+ else:
+ nh_found = True
+
+ if tag:
+ if "tag" not in rib_routes_json[st_rt][0]:
+ errormsg = (
+ "[DUT: {}]: tag is not"
+ " present for"
+ " route {} in RIB \n".format(dut, st_rt)
+ )
+ return errormsg
+
+ if _tag != rib_routes_json[st_rt][0]["tag"]:
+ errormsg = (
+ "[DUT: {}]: tag value {}"
+ " is not matched for"
+ " route {} in RIB \n".format(dut, _tag, st_rt,)
+ )
+ return errormsg
+
+ if metric is not None:
+ if "metric" not in rib_routes_json[st_rt][0]:
+ errormsg = (
+ "[DUT: {}]: metric is"
+ " not present for"
+ " route {} in RIB \n".format(dut, st_rt)
+ )
+ return errormsg
+
+ if metric != rib_routes_json[st_rt][0]["metric"]:
+ errormsg = (
+ "[DUT: {}]: metric value "
+ "{} is not matched for "
+ "route {} in RIB \n".format(dut, metric, st_rt,)
+ )
+ return errormsg
+
else:
missing_routes.append(st_rt)
if nh_found:
logger.info(
- "Found next_hop %s for all routes in RIB of" " router %s\n",
- next_hop,
- dut,
+ "[DUT: {}]: Found next_hop {} for all bgp"
+ " routes in RIB".format(router, next_hop)
)
- if not st_found and len(missing_routes) > 0:
- errormsg = (
- "Missing route in RIB of router {}, routes: "
- "{}\n".format(dut, missing_routes)
+ if len(missing_routes) > 0:
+ errormsg = "[DUT: {}]: Missing route in RIB, " "routes: {}".format(
+ dut, missing_routes
)
return errormsg
- logger.info(
- "Verified routes in router %s RIB, found routes" " are: %s\n",
- dut,
- found_routes,
- )
+ if found_routes:
+ logger.info(
+ "[DUT: %s]: Verified routes in RIB, found" " routes are: %s\n",
+ dut,
+ found_routes,
+ )
continue
if "bgp" in input_dict[routerInput]:
if (
"advertise_networks"
- in input_dict[routerInput]["bgp"]["address_family"][addr_type][
+ 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"]
+ found_routes = []
+ missing_routes = []
+ advertise_network = input_dict[routerInput]["bgp"]["address_family"][
+ addr_type
+ ]["unicast"]["advertise_networks"]
- for advertise_network_dict in advertise_network:
- 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)
- for st_rt in ip_list:
- st_rt = str(ipaddr.IPNetwork(unicode(st_rt)))
-
- found = False
- nh_found = False
- if st_rt in rib_routes_json:
- found = True
- found_routes.append(st_rt)
-
- if next_hop:
- if type(next_hop) is not list:
- next_hop = [next_hop]
-
- for index, nh in enumerate(next_hop):
- if (
- rib_routes_json[st_rt][0]["nexthops"][
- index
- ]["ip"]
- == nh
- ):
- nh_found = True
- else:
- errormsg = (
- "Nexthop {} is Missing"
- " for {} route {} in "
- "RIB of router {}\n".format(
- next_hop, protocol, st_rt, dut
- )
- )
- return errormsg
+ # 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)))
+
+ _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 nh_found:
- logger.info(
- "Found next_hop {} for all routes in RIB"
- " of router {}\n".format(next_hop, dut)
- )
+ if nh_found:
+ logger.info(
+ "Found next_hop {} for all routes in RIB"
+ " of router {}\n".format(next_hop, dut)
+ )
- if not found and len(missing_routes) > 0:
- errormsg = (
- "Missing {} route in RIB of router {}, "
- "routes: {} \n".format(addr_type, dut, missing_routes)
- )
- return errormsg
+ if len(missing_routes) > 0:
+ errormsg = (
+ "Missing {} route in RIB of router {}, "
+ "routes: {} \n".format(addr_type, dut, missing_routes)
+ )
+ return errormsg
+ if found_routes:
logger.info(
"Verified {} routes in router {} RIB, found"
" routes are: {}\n".format(addr_type, dut, found_routes)
)
- logger.debug("Exiting lib API: verify_rib()")
+ logger.info("Exiting lib API: verify_rib()")
return True
@@ -1788,7 +2479,6 @@ def verify_admin_distance_for_static_routes(tgen, input_dict):
"""
API to verify admin distance for static routes as defined in input_dict/
input JSON by running show ip/ipv6 route json command.
-
Parameter
---------
* `tgen` : topogen object
@@ -1808,13 +2498,12 @@ def verify_admin_distance_for_static_routes(tgen, input_dict):
}
}
result = verify_admin_distance_for_static_routes(tgen, input_dict)
-
Returns
-------
errormsg(str) or True
"""
- logger.debug("Entering lib API: verify_admin_distance_for_static_routes()")
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
for router in input_dict.keys():
if router not in tgen.routers():
@@ -1871,7 +2560,7 @@ def verify_admin_distance_for_static_routes(tgen, input_dict):
)
return errormsg
- logger.debug("Exiting lib API: verify_admin_distance_for_static_routes()")
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
return True
@@ -1879,12 +2568,10 @@ def verify_prefix_lists(tgen, input_dict):
"""
Running "show ip prefix-list" command and verifying given prefix-list
is present in router.
-
Parameters
----------
* `tgen` : topogen object
* `input_dict`: data to verify prefix lists
-
Usage
-----
# To verify pf_list_1 is present in router r1
@@ -1893,13 +2580,12 @@ def verify_prefix_lists(tgen, input_dict):
"prefix_lists": ["pf_list_1"]
}}
result = verify_prefix_lists("ipv4", input_dict, tgen)
-
Returns
-------
errormsg(str) or True
"""
- logger.debug("Entering lib API: verify_prefix_lists()")
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
for router in input_dict.keys():
if router not in tgen.routers():
@@ -1930,7 +2616,7 @@ def verify_prefix_lists(tgen, input_dict):
router,
)
- logger.debug("Exiting lib API: verify_prefix_lists()")
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
return True
@@ -1957,7 +2643,7 @@ def verify_route_maps(tgen, input_dict):
errormsg(str) or True
"""
- logger.debug("Entering lib API: verify_route_maps()")
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
for router in input_dict.keys():
if router not in tgen.routers():
@@ -1982,7 +2668,7 @@ def verify_route_maps(tgen, input_dict):
router,
)
- logger.debug("Exiting lib API: verify_route_maps()")
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
return True
@@ -1991,7 +2677,6 @@ def verify_bgp_community(tgen, addr_type, router, network, input_dict=None):
"""
API to veiryf BGP large community is attached in route for any given
DUT by running "show bgp ipv4/6 {route address} json" command.
-
Parameters
----------
* `tgen`: topogen object
@@ -2007,13 +2692,12 @@ def verify_bgp_community(tgen, addr_type, router, network, input_dict=None):
"largeCommunity": "2:1:1 2:2:2 2:3:3 2:4:4 2:5:5"
}
result = verify_bgp_community(tgen, "ipv4", dut, network, input_dict=None)
-
Returns
-------
errormsg(str) or True
"""
- logger.info("Entering lib API: verify_bgp_community()")
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
if router not in tgen.routers():
return False
@@ -2075,7 +2759,7 @@ def verify_bgp_community(tgen, addr_type, router, network, input_dict=None):
)
return errormsg
- logger.debug("Exiting lib API: verify_bgp_community()")
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
return True
@@ -2104,7 +2788,7 @@ def verify_create_community_list(tgen, input_dict):
errormsg(str) or True
"""
- logger.debug("Entering lib API: verify_create_community_list()")
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
for router in input_dict.keys():
if router not in tgen.routers():
@@ -2132,5 +2816,5 @@ def verify_create_community_list(tgen, input_dict):
)
return errormsg
- logger.debug("Exiting lib API: verify_create_community_list()")
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
return True
diff --git a/tests/topotests/lib/test/test_json.py b/tests/topotests/lib/test/test_json.py
index ba118d607a..7a061a9bc6 100755
--- a/tests/topotests/lib/test/test_json.py
+++ b/tests/topotests/lib/test/test_json.py
@@ -286,5 +286,216 @@ def test_json_list_start_failure():
assert json_cmp(dcomplete, dsub4) is not None
+def test_json_list_ordered():
+ "Test JSON encoded data that should be ordered using the '__ordered__' tag."
+
+ dcomplete = [
+ {"id": 1, "value": "abc"},
+ "some string",
+ 123,
+ ]
+
+ dsub1 = [
+ '__ordered__',
+ "some string",
+ {"id": 1, "value": "abc"},
+ 123,
+ ]
+
+ assert json_cmp(dcomplete, dsub1) is not None
+
+
+def test_json_list_exact_matching():
+ "Test JSON array on exact matching using the 'exact' parameter."
+
+ dcomplete = [
+ {"id": 1, "value": "abc"},
+ "some string",
+ 123,
+ [1,2,3],
+ ]
+
+ dsub1 = [
+ "some string",
+ {"id": 1, "value": "abc"},
+ 123,
+ [1,2,3],
+ ]
+
+ dsub2 = [
+ {"id": 1},
+ "some string",
+ 123,
+ [1,2,3],
+ ]
+
+ dsub3 = [
+ {"id": 1, "value": "abc"},
+ "some string",
+ 123,
+ [1,3,2],
+ ]
+
+ assert json_cmp(dcomplete, dsub1, exact=True) is not None
+ assert json_cmp(dcomplete, dsub2, exact=True) is not None
+
+
+def test_json_object_exact_matching():
+ "Test JSON object on exact matching using the 'exact' parameter."
+
+ dcomplete = {
+ 'a': {"id": 1, "value": "abc"},
+ 'b': "some string",
+ 'c': 123,
+ 'd': [1,2,3],
+ }
+
+ dsub1 = {
+ 'a': {"id": 1, "value": "abc"},
+ 'c': 123,
+ 'd': [1,2,3],
+ }
+
+ dsub2 = {
+ 'a': {"id": 1},
+ 'b': "some string",
+ 'c': 123,
+ 'd': [1,2,3],
+ }
+
+ dsub3 = {
+ 'a': {"id": 1, "value": "abc"},
+ 'b': "some string",
+ 'c': 123,
+ 'd': [1,3],
+ }
+
+ assert json_cmp(dcomplete, dsub1, exact=True) is not None
+ assert json_cmp(dcomplete, dsub2, exact=True) is not None
+ assert json_cmp(dcomplete, dsub3, exact=True) is not None
+
+
+def test_json_list_asterisk_matching():
+ "Test JSON array elements on matching '*' as a placeholder for arbitrary data."
+
+ dcomplete = [
+ {"id": 1, "value": "abc"},
+ "some string",
+ 123,
+ [1,2,3],
+ ]
+
+ dsub1 = [
+ '*',
+ "some string",
+ 123,
+ [1,2,3],
+ ]
+
+ dsub2 = [
+ {"id": '*', "value": "abc"},
+ "some string",
+ 123,
+ [1,2,3],
+ ]
+
+ dsub3 = [
+ {"id": 1, "value": "abc"},
+ "some string",
+ 123,
+ [1,'*',3],
+ ]
+
+ dsub4 = [
+ '*',
+ "some string",
+ '*',
+ [1,2,3],
+ ]
+
+ assert json_cmp(dcomplete, dsub1) is None
+ assert json_cmp(dcomplete, dsub2) is None
+ assert json_cmp(dcomplete, dsub3) is None
+ assert json_cmp(dcomplete, dsub4) is None
+
+
+def test_json_object_asterisk_matching():
+ "Test JSON object value elements on matching '*' as a placeholder for arbitrary data."
+
+ dcomplete = {
+ 'a': {"id": 1, "value": "abc"},
+ 'b': "some string",
+ 'c': 123,
+ 'd': [1,2,3],
+ }
+
+ dsub1 = {
+ 'a': '*',
+ 'b': "some string",
+ 'c': 123,
+ 'd': [1,2,3],
+ }
+
+ dsub2 = {
+ 'a': {"id": 1, "value": "abc"},
+ 'b': "some string",
+ 'c': 123,
+ 'd': [1,'*',3],
+ }
+
+ dsub3 = {
+ 'a': {"id": '*', "value": "abc"},
+ 'b': "some string",
+ 'c': 123,
+ 'd': [1,2,3],
+ }
+
+ dsub4 = {
+ 'a': '*',
+ 'b': "some string",
+ 'c': '*',
+ 'd': [1,2,3],
+ }
+
+ assert json_cmp(dcomplete, dsub1) is None
+ assert json_cmp(dcomplete, dsub2) is None
+ assert json_cmp(dcomplete, dsub3) is None
+ assert json_cmp(dcomplete, dsub4) is None
+
+
+def test_json_list_nested_with_objects():
+
+ dcomplete = [
+ {
+ "key": 1,
+ "list": [
+ 123
+ ]
+ },
+ {
+ "key": 2,
+ "list": [
+ 123
+ ]
+ }
+ ]
+
+ dsub1 = [
+ {
+ "key": 2,
+ "list": [
+ 123
+ ]
+ },
+ {
+ "key": 1,
+ "list": [
+ 123
+ ]
+ }
+ ]
+
+ assert json_cmp(dcomplete, dsub1) is None
+
if __name__ == "__main__":
sys.exit(pytest.main())
diff --git a/tests/topotests/lib/topogen.py b/tests/topotests/lib/topogen.py
index 6a6bbc7c78..673d65376f 100644
--- a/tests/topotests/lib/topogen.py
+++ b/tests/topotests/lib/topogen.py
@@ -555,6 +555,7 @@ class TopoRouter(TopoGear):
RD_STATIC = 12
RD_BFD = 13
RD_SHARP = 14
+ RD_BABEL = 15
RD = {
RD_ZEBRA: "zebra",
RD_RIP: "ripd",
@@ -570,6 +571,7 @@ class TopoRouter(TopoGear):
RD_STATIC: "staticd",
RD_BFD: "bfdd",
RD_SHARP: "sharpd",
+ RD_BABEL: "babeld",
}
def __init__(self, tgen, cls, name, **params):
@@ -707,6 +709,38 @@ class TopoRouter(TopoGear):
self.logger.debug("stopping")
return self.tgen.net[self.name].stopRouter(wait, assertOnError)
+ def startDaemons(self, daemons):
+ """
+ Start Daemons: to start specific daemon(user defined daemon only)
+ * Start daemons (e.g. FRR/Quagga)
+ * Configure daemon logging files
+ """
+ self.logger.debug('starting')
+ nrouter = self.tgen.net[self.name]
+ result = nrouter.startRouterDaemons(daemons)
+
+ # Enable all daemon command logging, logging files
+ # and set them to the start dir.
+ for daemon, enabled in nrouter.daemons.iteritems():
+ for d in daemons:
+ if enabled == 0:
+ continue
+ self.vtysh_cmd('configure terminal\nlog commands\nlog file {}.log'.\
+ format(daemon), daemon=daemon)
+
+ if result != '':
+ self.tgen.set_error(result)
+
+ return result
+
+ def killDaemons(self, daemons, wait=True, assertOnError=True):
+ """
+ Kill specific daemon(user defined daemon only)
+ forcefully using SIGKILL
+ """
+ self.logger.debug('Killing daemons using SIGKILL..')
+ return self.tgen.net[self.name].killRouterDaemons(daemons, wait, assertOnError)
+
def vtysh_cmd(self, command, isjson=False, daemon=None):
"""
Runs the provided command string in the vty shell and returns a string
diff --git a/tests/topotests/lib/topojson.py b/tests/topotests/lib/topojson.py
index b25317ba7f..24b61981d6 100644
--- a/tests/topotests/lib/topojson.py
+++ b/tests/topotests/lib/topojson.py
@@ -37,6 +37,7 @@ from lib.common_config import (
create_prefix_lists,
create_route_maps,
create_bgp_community_lists,
+ create_vrf_cfg,
)
from lib.bgp import create_router_bgp
@@ -49,7 +50,6 @@ def build_topo_from_json(tgen, topo):
Reads configuration from JSON file. Adds routers, creates interface
names dynamically and link routers as defined in JSON to create
topology. Assigns IPs dynamically to all interfaces of each router.
-
* `tgen`: Topogen object
* `topo`: json file data
"""
@@ -203,6 +203,7 @@ def build_config_from_json(tgen, topo, save_bkup=True):
func_dict = OrderedDict(
[
+ ("vrfs", create_vrf_cfg),
("links", create_interfaces_cfg),
("static_routes", create_static_routes),
("prefix_lists", create_prefix_lists),
diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py
index fab101cb25..b35606df8f 100644
--- a/tests/topotests/lib/topotest.py
+++ b/tests/topotests/lib/topotest.py
@@ -37,6 +37,7 @@ import difflib
import time
from lib.topolog import logger
+from copy import deepcopy
if sys.version_info[0] > 2:
import configparser
@@ -66,144 +67,212 @@ class json_cmp_result(object):
"Returns True if there were errors, otherwise False."
return len(self.errors) > 0
+ def gen_report(self):
+ headline = ["Generated JSON diff error report:", ""]
+ return headline + self.errors
+
def __str__(self):
- return "\n".join(self.errors)
+ return (
+ "Generated JSON diff error report:\n\n\n" + "\n".join(self.errors) + "\n\n"
+ )
-def json_diff(d1, d2):
+def gen_json_diff_report(d1, d2, exact=False, path="> $", acc=(0, "")):
"""
- Returns a string with the difference between JSON data.
+ Internal workhorse which compares two JSON data structures and generates an error report suited to be read by a human eye.
"""
- json_format_opts = {
- "indent": 4,
- "sort_keys": True,
- }
- dstr1 = json.dumps(d1, **json_format_opts)
- dstr2 = json.dumps(d2, **json_format_opts)
- return difflines(dstr2, dstr1, title1="Expected value", title2="Current value", n=0)
-
-
-def _json_list_cmp(list1, list2, parent, result):
- "Handles list type entries."
- # Check second list2 type
- if not isinstance(list1, type([])) or not isinstance(list2, type([])):
- result.add_error(
- "{} has different type than expected ".format(parent)
- + "(have {}, expected {}):\n{}".format(
- type(list1), type(list2), json_diff(list1, list2)
+
+ def dump_json(v):
+ if isinstance(v, (dict, list)):
+ return "\t" + "\t".join(
+ json.dumps(v, indent=4, separators=(",", ": ")).splitlines(True)
)
+ else:
+ return "'{}'".format(v)
+
+ def json_type(v):
+ if isinstance(v, (list, tuple)):
+ return "Array"
+ elif isinstance(v, dict):
+ return "Object"
+ elif isinstance(v, (int, float)):
+ return "Number"
+ elif isinstance(v, bool):
+ return "Boolean"
+ elif isinstance(v, str):
+ return "String"
+ elif v == None:
+ return "null"
+
+ def get_errors(other_acc):
+ return other_acc[1]
+
+ def get_errors_n(other_acc):
+ return other_acc[0]
+
+ def add_error(acc, msg, points=1):
+ return (acc[0] + points, acc[1] + "{}: {}\n".format(path, msg))
+
+ def merge_errors(acc, other_acc):
+ return (acc[0] + other_acc[0], acc[1] + other_acc[1])
+
+ def add_idx(idx):
+ return "{}[{}]".format(path, idx)
+
+ def add_key(key):
+ return "{}->{}".format(path, key)
+
+ def has_errors(other_acc):
+ return other_acc[0] > 0
+
+ if d2 == "*" or (
+ not isinstance(d1, (list, dict))
+ and not isinstance(d2, (list, dict))
+ and d1 == d2
+ ):
+ return acc
+ elif (
+ not isinstance(d1, (list, dict))
+ and not isinstance(d2, (list, dict))
+ and d1 != d2
+ ):
+ acc = add_error(
+ acc,
+ "d1 has element with value '{}' but in d2 it has value '{}'".format(d1, d2),
)
- return
-
- # Check list size
- if len(list2) > len(list1):
- result.add_error(
- "{} too few items ".format(parent)
- + "(have {}, expected {}:\n {})".format(
- len(list1), len(list2), json_diff(list1, list2)
+ elif (
+ isinstance(d1, list)
+ and isinstance(d2, list)
+ and ((len(d2) > 0 and d2[0] == "__ordered__") or exact)
+ ):
+ if not exact:
+ del d2[0]
+ if len(d1) != len(d2):
+ acc = add_error(
+ acc,
+ "d1 has Array of length {} but in d2 it is of length {}".format(
+ len(d1), len(d2)
+ ),
)
+ else:
+ for idx, v1, v2 in zip(range(0, len(d1)), d1, d2):
+ acc = merge_errors(
+ acc, gen_json_diff_report(v1, v2, exact=exact, path=add_idx(idx))
+ )
+ elif isinstance(d1, list) and isinstance(d2, list):
+ if len(d1) < len(d2):
+ acc = add_error(
+ acc,
+ "d1 has Array of length {} but in d2 it is of length {}".format(
+ len(d1), len(d2)
+ ),
+ )
+ else:
+ for idx2, v2 in zip(range(0, len(d2)), d2):
+ found_match = False
+ closest_diff = None
+ closest_idx = None
+ for idx1, v1 in zip(range(0, len(d1)), d1):
+ tmp_v1 = deepcopy(v1)
+ tmp_v2 = deepcopy(v2)
+ tmp_diff = gen_json_diff_report(tmp_v1, tmp_v2, path=add_idx(idx1))
+ if not has_errors(tmp_diff):
+ found_match = True
+ del d1[idx1]
+ break
+ elif not closest_diff or get_errors_n(tmp_diff) < get_errors_n(
+ closest_diff
+ ):
+ closest_diff = tmp_diff
+ closest_idx = idx1
+ if not found_match and isinstance(v2, (list, dict)):
+ sub_error = "\n\n\t{}".format(
+ "\t".join(get_errors(closest_diff).splitlines(True))
+ )
+ acc = add_error(
+ acc,
+ (
+ "d2 has the following element at index {} which is not present in d1: "
+ + "\n\n{}\n\n\tClosest match in d1 is at index {} with the following errors: {}"
+ ).format(idx2, dump_json(v2), closest_idx, sub_error),
+ )
+ if not found_match and not isinstance(v2, (list, dict)):
+ acc = add_error(
+ acc,
+ "d2 has the following element at index {} which is not present in d1: {}".format(
+ idx2, dump_json(v2)
+ ),
+ )
+ elif isinstance(d1, dict) and isinstance(d2, dict) and exact:
+ invalid_keys_d1 = [k for k in d1.keys() if k not in d2.keys()]
+ invalid_keys_d2 = [k for k in d2.keys() if k not in d1.keys()]
+ for k in invalid_keys_d1:
+ acc = add_error(acc, "d1 has key '{}' which is not present in d2".format(k))
+ for k in invalid_keys_d2:
+ acc = add_error(acc, "d2 has key '{}' which is not present in d1".format(k))
+ valid_keys_intersection = [k for k in d1.keys() if k in d2.keys()]
+ for k in valid_keys_intersection:
+ acc = merge_errors(
+ acc, gen_json_diff_report(d1[k], d2[k], exact=exact, path=add_key(k))
+ )
+ elif isinstance(d1, dict) and isinstance(d2, dict):
+ none_keys = [k for k, v in d2.items() if v == None]
+ none_keys_present = [k for k in d1.keys() if k in none_keys]
+ for k in none_keys_present:
+ acc = add_error(
+ acc, "d1 has key '{}' which is not supposed to be present".format(k)
+ )
+ keys = [k for k, v in d2.items() if v != None]
+ invalid_keys_intersection = [k for k in keys if k not in d1.keys()]
+ for k in invalid_keys_intersection:
+ acc = add_error(acc, "d2 has key '{}' which is not present in d1".format(k))
+ valid_keys_intersection = [k for k in keys if k in d1.keys()]
+ for k in valid_keys_intersection:
+ acc = merge_errors(
+ acc, gen_json_diff_report(d1[k], d2[k], exact=exact, path=add_key(k))
+ )
+ else:
+ acc = add_error(
+ acc,
+ "d1 has element of type '{}' but the corresponding element in d2 is of type '{}'".format(
+ json_type(d1), json_type(d2)
+ ),
+ points=2,
)
- return
-
- # List all unmatched items errors
- unmatched = []
- for expected in list2:
- matched = False
- for value in list1:
- if json_cmp({"json": value}, {"json": expected}) is None:
- matched = True
- break
-
- if not matched:
- unmatched.append(expected)
-
- # If there are unmatched items, error out.
- if unmatched:
- result.add_error(
- "{} value is different (\n{})".format(parent, json_diff(list1, list2))
- )
+
+ return acc
-def json_cmp(d1, d2):
+def json_cmp(d1, d2, exact=False):
"""
JSON compare function. Receives two parameters:
- * `d1`: json value
- * `d2`: json subset which we expect
-
- Returns `None` when all keys that `d1` has matches `d2`,
- otherwise a string containing what failed.
-
- Note: key absence can be tested by adding a key with value `None`.
+ * `d1`: parsed JSON data structure
+ * `d2`: parsed JSON data structure
+
+ Returns 'None' when all JSON Object keys and all Array elements of d2 have a match
+ in d1, e.g. when d2 is a "subset" of d1 without honoring any order. Otherwise an
+ error report is generated and wrapped in a 'json_cmp_result()'. There are special
+ parameters and notations explained below which can be used to cover rather unusual
+ cases:
+
+ * when 'exact is set to 'True' then d1 and d2 are tested for equality (including
+ order within JSON Arrays)
+ * using 'null' (or 'None' in Python) as JSON Object value is checking for key
+ absence in d1
+ * using '*' as JSON Object value or Array value is checking for presence in d1
+ without checking the values
+ * using '__ordered__' as first element in a JSON Array in d2 will also check the
+ order when it is compared to an Array in d1
"""
- squeue = [(d1, d2, "json")]
- result = json_cmp_result()
-
- for s in squeue:
- nd1, nd2, parent = s
-
- # Handle JSON beginning with lists.
- if isinstance(nd1, type([])) or isinstance(nd2, type([])):
- _json_list_cmp(nd1, nd2, parent, result)
- if result.has_errors():
- return result
- else:
- return None
-
- # Expect all required fields to exist.
- s1, s2 = set(nd1), set(nd2)
- s2_req = set([key for key in nd2 if nd2[key] is not None])
- diff = s2_req - s1
- if diff != set({}):
- result.add_error(
- "expected key(s) {} in {} (have {}):\n{}".format(
- str(list(diff)), parent, str(list(s1)), json_diff(nd1, nd2)
- )
- )
-
- for key in s2.intersection(s1):
- # Test for non existence of key in d2
- if nd2[key] is None:
- result.add_error(
- '"{}" should not exist in {} (have {}):\n{}'.format(
- key, parent, str(s1), json_diff(nd1[key], nd2[key])
- )
- )
- continue
-
- # If nd1 key is a dict, we have to recurse in it later.
- if isinstance(nd2[key], type({})):
- if not isinstance(nd1[key], type({})):
- result.add_error(
- '{}["{}"] has different type than expected '.format(parent, key)
- + "(have {}, expected {}):\n{}".format(
- type(nd1[key]),
- type(nd2[key]),
- json_diff(nd1[key], nd2[key]),
- )
- )
- continue
- nparent = '{}["{}"]'.format(parent, key)
- squeue.append((nd1[key], nd2[key], nparent))
- continue
- # Check list items
- if isinstance(nd2[key], type([])):
- _json_list_cmp(nd1[key], nd2[key], parent, result)
- continue
+ (errors_n, errors) = gen_json_diff_report(deepcopy(d1), deepcopy(d2), exact=exact)
- # Compare JSON values
- if nd1[key] != nd2[key]:
- result.add_error(
- '{}["{}"] value is different (\n{})'.format(
- parent, key, json_diff(nd1[key], nd2[key])
- )
- )
- continue
-
- if result.has_errors():
+ if errors_n > 0:
+ result = json_cmp_result()
+ result.add_error(errors)
return result
-
- return None
+ else:
+ return None
def router_output_cmp(router, cmd, expected):
@@ -218,12 +287,12 @@ def router_output_cmp(router, cmd, expected):
)
-def router_json_cmp(router, cmd, data):
+def router_json_cmp(router, cmd, data, exact=False):
"""
Runs `cmd` that returns JSON data (normally the command ends with 'json')
and compare with `data` contents.
"""
- return json_cmp(router.vtysh_cmd(cmd, isjson=True), data)
+ return json_cmp(router.vtysh_cmd(cmd, isjson=True), data, exact)
def run_and_expect(func, what, count=20, wait=3):
@@ -801,6 +870,7 @@ class Router(Node):
"staticd": 0,
"bfdd": 0,
"sharpd": 0,
+ "babeld": 0,
}
self.daemons_options = {"zebra": ""}
self.reportCores = True
@@ -1088,6 +1158,120 @@ class Router(Node):
def getLog(self, log, daemon):
return self.cmd("cat {}/{}/{}.{}".format(self.logdir, self.name, daemon, log))
+ def startRouterDaemons(self, daemons):
+ # Starts actual daemons without init (ie restart)
+ # cd to per node directory
+ self.cmd('cd {}/{}'.format(self.logdir, self.name))
+ self.cmd('umask 000')
+ #Re-enable to allow for report per run
+ self.reportCores = True
+ rundaemons = self.cmd('ls -1 /var/run/%s/*.pid' % self.routertype)
+
+ for daemon in daemons:
+ if daemon == 'zebra':
+ # Start Zebra first
+ if self.daemons['zebra'] == 1:
+ zebra_path = os.path.join(self.daemondir, 'zebra')
+ zebra_option = self.daemons_options['zebra']
+ self.cmd('{0} {1} > zebra.out 2> zebra.err &'.format(
+ zebra_path, zebra_option, self.logdir, self.name
+ ))
+ self.waitOutput()
+ logger.debug('{}: {} zebra started'.format(self, self.routertype))
+ sleep(1, '{}: waiting for zebra to start'.format(self.name))
+
+ # Fix Link-Local Addresses
+ # Somehow (on Mininet only), Zebra removes the IPv6 Link-Local
+ # addresses on start. Fix this
+ self.cmd('for i in `ls /sys/class/net/` ; do mac=`cat /sys/class/net/$i/address`; IFS=\':\'; set $mac; unset IFS; ip address add dev $i scope link fe80::$(printf %02x $((0x$1 ^ 2)))$2:${3}ff:fe$4:$5$6/64; done')
+
+ if daemon == 'staticd':
+ # Start staticd next if required
+ if self.daemons['staticd'] == 1:
+ staticd_path = os.path.join(self.daemondir, 'staticd')
+ staticd_option = self.daemons_options['staticd']
+ self.cmd('{0} {1} > staticd.out 2> staticd.err &'.format(
+ staticd_path, staticd_option, self.logdir, self.name
+ ))
+ self.waitOutput()
+ logger.debug('{}: {} staticd started'.format(self, self.routertype))
+ sleep(1, '{}: waiting for staticd to start'.format(self.name))
+
+ # Now start all the daemons
+ # Skip disabled daemons and zebra
+ if self.daemons[daemon] == 0 or daemon == 'zebra' or daemon == 'staticd':
+ continue
+ daemon_path = os.path.join(self.daemondir, daemon)
+ self.cmd('{0} > {1}.out 2> {1}.err &'.format(
+ daemon_path, daemon
+ ))
+ self.waitOutput()
+ logger.debug('{}: {} {} started'.format(self, self.routertype, daemon))
+ sleep(1, '{}: waiting for {} to start'.format(self.name, daemon))
+
+ rundaemons = self.cmd('ls -1 /var/run/%s/*.pid' % self.routertype)
+
+ if re.search(r"No such file or directory", rundaemons):
+ return "Daemons are not running"
+
+ return ""
+
+ def killRouterDaemons(self, daemons, wait=True, assertOnError=True,
+ minErrorVersion='5.1'):
+ # Kill Running Quagga or FRR specific
+ # Daemons(user specified daemon only) using SIGKILL
+ rundaemons = self.cmd('ls -1 /var/run/%s/*.pid' % self.routertype)
+ errors = ""
+ daemonsNotRunning = []
+ if re.search(r"No such file or directory", rundaemons):
+ return errors
+ for daemon in daemons:
+ if rundaemons is not None and daemon in rundaemons:
+ numRunning = 0
+ for d in StringIO.StringIO(rundaemons):
+ if re.search(r"%s" % daemon, d):
+ daemonpid = self.cmd('cat %s' % d.rstrip()).rstrip()
+ if (daemonpid.isdigit() and pid_exists(int(daemonpid))):
+ logger.info('{}: killing {}'.format(
+ self.name,
+ os.path.basename(d.rstrip().rsplit(".", 1)[0])
+ ))
+ self.cmd('kill -9 %s' % daemonpid)
+ self.waitOutput()
+ if pid_exists(int(daemonpid)):
+ numRunning += 1
+ if wait and numRunning > 0:
+ sleep(2, '{}: waiting for {} daemon to be stopped'.\
+ format(self.name, daemon))
+ # 2nd round of kill if daemons didn't exit
+ for d in StringIO.StringIO(rundaemons):
+ if re.search(r"%s" % daemon, d):
+ daemonpid = \
+ self.cmd('cat %s' % d.rstrip()).rstrip()
+ if (daemonpid.isdigit() and pid_exists(
+ int(daemonpid))):
+ logger.info('{}: killing {}'.format(
+ self.name,
+ os.path.basename(d.rstrip().\
+ rsplit(".", 1)[0])
+ ))
+ self.cmd('kill -9 %s' % daemonpid)
+ self.waitOutput()
+ self.cmd('rm -- {}'.format(d.rstrip()))
+ if wait:
+ errors = self.checkRouterCores(reportOnce=True)
+ if self.checkRouterVersion('<', minErrorVersion):
+ #ignore errors in old versions
+ errors = ""
+ if assertOnError and len(errors) > 0:
+ assert "Errors found - details follow:" == 0, errors
+ else:
+ daemonsNotRunning.append(daemon)
+ if len(daemonsNotRunning) > 0:
+ errors = errors+"Daemons are not running", daemonsNotRunning
+
+ return errors
+
def checkRouterCores(self, reportLeaks=True, reportOnce=False):
if reportOnce and not self.reportCores:
return
diff --git a/tools/frr-reload.py b/tools/frr-reload.py
index 1f9f425386..c10eb487e6 100755
--- a/tools/frr-reload.py
+++ b/tools/frr-reload.py
@@ -155,7 +155,7 @@ class Config(object):
try:
config_text = subprocess.check_output(
bindir + "/vtysh --config_dir " + confdir + " -c 'show run " + daemon + "' | /usr/bin/tail -n +4 | " + bindir + "/vtysh --config_dir " + confdir + " -m -f -",
- shell=True)
+ shell=True, stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as e:
ve = VtyshMarkException(e)
ve.output = e.output
@@ -779,13 +779,14 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del):
bfd_search_string = bfd_nbr + r' bfd (\S+) (\S+) (\S+)'
for (ctx_keys, add_line) in lines_to_add:
- re_add_nbr_bfd_timers = re.search(bfd_search_string, add_line)
+ if ctx_keys[0].startswith('router bgp'):
+ re_add_nbr_bfd_timers = re.search(bfd_search_string, add_line)
- if re_add_nbr_bfd_timers:
- found_add_bfd_nbr = line_exist(lines_to_add, ctx_keys, bfd_nbr, False)
+ if re_add_nbr_bfd_timers:
+ found_add_bfd_nbr = line_exist(lines_to_add, ctx_keys, bfd_nbr, False)
- if found_add_bfd_nbr:
- lines_to_del_to_del.append((ctx_keys, line))
+ if found_add_bfd_nbr:
+ lines_to_del_to_del.append((ctx_keys, line))
'''
We changed how we display the neighbor interface command. Older
@@ -1135,7 +1136,7 @@ def vtysh_config_available(bindir, confdir):
try:
cmd = [str(bindir + '/vtysh'), '--config_dir', confdir, '-c', 'conf t']
- output = subprocess.check_output(cmd).strip()
+ output = subprocess.check_output(cmd, stderr=subprocess.STDOUT).strip()
if 'VTY configuration is locked by other VTY' in output.decode('utf-8'):
print(output)
@@ -1393,7 +1394,7 @@ if __name__ == '__main__':
while True:
try:
- _ = subprocess.check_output(cmd)
+ _ = subprocess.check_output(cmd, stderr=subprocess.STDOUT)
except subprocess.CalledProcessError:
@@ -1443,7 +1444,7 @@ if __name__ == '__main__':
fh.write(line + '\n')
try:
- subprocess.check_output([str(args.bindir + '/vtysh'), '--config_dir', args.confdir, '-f', filename])
+ subprocess.check_output([str(args.bindir + '/vtysh'), '--config_dir', args.confdir, '-f', filename], stderr=subprocess.STDOUT)
except subprocess.CalledProcessError as e:
log.warning("frr-reload.py failed due to\n%s" % e.output)
reload_ok = False
diff --git a/tools/frr.in b/tools/frr.in
index d9816c2568..40862aa4c9 100755
--- a/tools/frr.in
+++ b/tools/frr.in
@@ -21,6 +21,7 @@ VTYSH="@vtysh_bin@" # /usr/bin/vtysh
FRR_USER="@enable_user@" # frr
FRR_GROUP="@enable_group@" # frr
FRR_VTY_GROUP="@enable_vty_group@" # frrvty
+FRR_CONFIG_MODE="@enable_configfile_mask@" # 0600
FRR_DEFAULT_PROFILE="@DFLT_NAME@" # traditional / datacenter
# Local Daemon selection may be done by using /etc/frr/daemons.
@@ -56,6 +57,7 @@ chownfrr()
{
test -n "$FRR_USER" && chown "$FRR_USER" "$1"
test -n "$FRR_GROUP" && chgrp "$FRR_GROUP" "$1"
+ test -n "$FRR_CONFIG_MODE" && chmod "$FRR_CONFIG_MODE" "$1"
}
# Check if daemon is started by using the pidfile.
diff --git a/tools/frrcommon.sh.in b/tools/frrcommon.sh.in
index 0dfdfd0efa..2955f74ce3 100644
--- a/tools/frrcommon.sh.in
+++ b/tools/frrcommon.sh.in
@@ -24,6 +24,7 @@ VTYSH="@vtysh_bin@" # /usr/bin/vtysh
FRR_USER="@enable_user@" # frr
FRR_GROUP="@enable_group@" # frr
FRR_VTY_GROUP="@enable_vty_group@" # frrvty
+FRR_CONFIG_MODE="@enable_configfile_mask@" # 0600
FRR_DEFAULT_PROFILE="@DFLT_NAME@" # traditional / datacenter
# ORDER MATTERS FOR $DAEMONS!
@@ -53,6 +54,7 @@ debug() {
chownfrr() {
[ -n "$FRR_USER" ] && chown "$FRR_USER" "$1"
[ -n "$FRR_GROUP" ] && chgrp "$FRR_GROUP" "$1"
+ [ -n "$FRR_CONFIG_MODE" ] && chmod "$FRR_CONFIG_MODE" "$1"
}
vtysh_b () {
@@ -90,7 +92,7 @@ daemon_list() {
continue
fi
debug "$daemon enabled"
- enabled="$enabled $daemon"
+
if [ -n "$inst" ]; then
debug "$daemon multi-instance $inst"
oldifs="${IFS}"
@@ -99,6 +101,8 @@ daemon_list() {
enabled="$enabled $daemon-$i"
done
IFS="${oldifs}"
+ else
+ enabled="$enabled $daemon"
fi
else
debug "$daemon disabled"
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index 15ec866fc9..21280ec7aa 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -1492,6 +1492,13 @@ static struct cmd_node bfd_peer_node = {
.parent_node = BFD_NODE,
.prompt = "%s(config-bfd-peer)# ",
};
+
+static struct cmd_node bfd_profile_node = {
+ .name = "bfd profile",
+ .node = BFD_PROFILE_NODE,
+ .parent_node = BFD_NODE,
+ .prompt = "%s(config-bfd-profile)# ",
+};
#endif /* HAVE_BFDD */
/* Defined in lib/vty.c */
@@ -1947,6 +1954,15 @@ DEFUNSH(VTYSH_BFDD, bfd_peer_enter, bfd_peer_enter_cmd,
vty->node = BFD_PEER_NODE;
return CMD_SUCCESS;
}
+
+DEFUNSH(VTYSH_BFDD, bfd_profile_enter, bfd_profile_enter_cmd,
+ "profile WORD",
+ BFD_PROFILE_STR
+ BFD_PROFILE_NAME_STR)
+{
+ vty->node = BFD_PROFILE_NODE;
+ return CMD_SUCCESS;
+}
#endif /* HAVE_BFDD */
DEFSH(VTYSH_PBRD, vtysh_no_pbr_map_cmd, "no pbr-map PBRMAP [seq (1-700)]",
@@ -3796,6 +3812,7 @@ void vtysh_init_vty(void)
#if HAVE_BFDD > 0
install_node(&bfd_node);
install_node(&bfd_peer_node);
+ install_node(&bfd_profile_node);
#endif /* HAVE_BFDD */
struct cmd_node *node;
@@ -3897,16 +3914,20 @@ void vtysh_init_vty(void)
/* Enter node. */
install_element(CONFIG_NODE, &bfd_enter_cmd);
install_element(BFD_NODE, &bfd_peer_enter_cmd);
+ install_element(BFD_NODE, &bfd_profile_enter_cmd);
/* Exit/quit node. */
install_element(BFD_NODE, &vtysh_exit_bfdd_cmd);
install_element(BFD_NODE, &vtysh_quit_bfdd_cmd);
install_element(BFD_PEER_NODE, &vtysh_exit_bfdd_cmd);
install_element(BFD_PEER_NODE, &vtysh_quit_bfdd_cmd);
+ install_element(BFD_PROFILE_NODE, &vtysh_exit_bfdd_cmd);
+ install_element(BFD_PROFILE_NODE, &vtysh_quit_bfdd_cmd);
/* End/exit all. */
install_element(BFD_NODE, &vtysh_end_all_cmd);
install_element(BFD_PEER_NODE, &vtysh_end_all_cmd);
+ install_element(BFD_PROFILE_NODE, &vtysh_end_all_cmd);
#endif /* HAVE_BFDD */
install_element(VTY_NODE, &vtysh_exit_line_vty_cmd);
install_element(VTY_NODE, &vtysh_quit_line_vty_cmd);
diff --git a/yang/LICENSE b/yang/LICENSE
new file mode 100644
index 0000000000..a7cec5de91
--- /dev/null
+++ b/yang/LICENSE
@@ -0,0 +1,22 @@
+Copyright 2020 FRRouting
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice,
+this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+this list of conditions and the following disclaimer in the documentation
+and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/yang/frr-bfdd.yang b/yang/frr-bfdd.yang
index b870bfd0c8..13bad27b19 100644
--- a/yang/frr-bfdd.yang
+++ b/yang/frr-bfdd.yang
@@ -21,7 +21,32 @@ module frr-bfdd {
"FRR Users List: <mailto:frog@lists.frrouting.org>
FRR Development List: <mailto:dev@lists.frrouting.org>";
description
- "This module defines a model for managing FRR bfdd daemon.";
+ "This module defines a model for managing FRR bfdd daemon.
+
+ Copyright 2020 FRRouting
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";
revision 2019-05-09 {
description "Initial revision.";
@@ -29,7 +54,7 @@ module frr-bfdd {
"RFC 5880: Bidirectional Forwarding Detection (BFD).
RFC 5881: Bidirectional Forwarding Detection (BFD)
for IPv4 and IPv6 (Single Hop).
- RFC 5882: Bidirectional Forwarding Detection (BFD) for Multihop Paths.";
+ RFC 5883: Bidirectional Forwarding Detection (BFD) for Multihop Paths.";
}
@@ -114,6 +139,21 @@ module frr-bfdd {
}
}
+ typedef profile-name {
+ type string {
+ length "1..64";
+ }
+ description "Profile name format";
+ }
+
+ typedef profile-ref {
+ type leafref {
+ path "/frr-bfdd:bfdd/frr-bfdd:bfd/frr-bfdd:profile/frr-bfdd:name";
+ require-instance false;
+ }
+ description "Reference to a BFD profile";
+ }
+
/*
* Shared BFD items.
*/
@@ -312,6 +352,19 @@ module frr-bfdd {
container bfd {
presence "Present if the BFD protocol is enabled";
+ list profile {
+ key "name";
+ description "BFD pre configuration profiles";
+
+ leaf name {
+ type profile-name;
+ description "Profile name";
+ }
+
+ uses session-common;
+ uses session-echo;
+ }
+
container sessions {
list single-hop {
key "dest-addr interface vrf";
@@ -339,6 +392,11 @@ module frr-bfdd {
description "Local IP address";
}
+ leaf profile {
+ type profile-ref;
+ description "Override defaults with profile.";
+ }
+
uses session-common;
uses session-echo;
@@ -374,6 +432,11 @@ module frr-bfdd {
description "Virtual Routing Domain name";
}
+ leaf profile {
+ type profile-ref;
+ description "Override defaults with profile.";
+ }
+
uses session-common;
container stats {
diff --git a/yang/frr-eigrpd.yang b/yang/frr-eigrpd.yang
index 092b714045..3d1bf3baa5 100644
--- a/yang/frr-eigrpd.yang
+++ b/yang/frr-eigrpd.yang
@@ -21,7 +21,32 @@ module frr-eigrpd {
"FRR Users List: <mailto:frog@lists.frrouting.org>
FRR Development List: <mailto:dev@lists.frrouting.org>";
description
- "This module defines a model for managing FRR eigrpd daemon.";
+ "This module defines a model for managing FRR eigrpd daemon.
+
+ Copyright 2020 FRRouting
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";
revision 2019-09-09 {
description
diff --git a/yang/frr-filter.yang b/yang/frr-filter.yang
index 61ffa51552..c55af34161 100644
--- a/yang/frr-filter.yang
+++ b/yang/frr-filter.yang
@@ -14,7 +14,33 @@ module frr-filter {
contact
"FRR Users List: <mailto:frog@lists.frrouting.org>
FRR Development List: <mailto:dev@lists.frrouting.org>";
- description "This module defines filter settings";
+ description
+ "This module defines filter settings
+
+ Copyright 2020 FRRouting
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";
revision 2019-07-04 {
description "Initial revision";
diff --git a/yang/frr-igmp.yang b/yang/frr-igmp.yang
index 534fd78480..b63d0f97ec 100644
--- a/yang/frr-igmp.yang
+++ b/yang/frr-igmp.yang
@@ -28,7 +28,32 @@ module frr-igmp {
FRR Development List: <mailto:dev@lists.frrouting.org>";
description
- "This module defines a model for managing FRR pimd daemon.";
+ "This module defines a model for managing FRR pimd daemon.
+
+ Copyright 2020 FRRouting
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";
revision 2019-11-06 {
description
diff --git a/yang/frr-interface.yang b/yang/frr-interface.yang
index 7ebba935a4..dade9f97fe 100644
--- a/yang/frr-interface.yang
+++ b/yang/frr-interface.yang
@@ -21,7 +21,32 @@ module frr-interface {
"FRR Users List: <mailto:frog@lists.frrouting.org>
FRR Development List: <mailto:dev@lists.frrouting.org>";
description
- "This module defines a model for managing FRR interfaces.";
+ "This module defines a model for managing FRR interfaces.
+
+ Copyright 2020 FRRouting
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";
revision 2020-02-05 {
description
diff --git a/yang/frr-isisd.yang b/yang/frr-isisd.yang
index 57f81892e0..445a59bc8a 100644
--- a/yang/frr-isisd.yang
+++ b/yang/frr-isisd.yang
@@ -25,7 +25,32 @@ module frr-isisd {
"FRR Users List: <mailto:frog@lists.frrouting.org> FRR Development
List: <mailto:dev@lists.frrouting.org>";
description
- "This module defines a model for managing FRR isisd daemon.";
+ "This module defines a model for managing FRR isisd daemon.
+
+ Copyright 2020 FRRouting
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";
revision 2020-04-06 {
description
@@ -1161,6 +1186,107 @@ module frr-isisd {
"Stable IP address of the advertising router.";
}
}
+
+ container segment-routing {
+ description
+ "Segment Routing global configuration.";
+ leaf enabled {
+ type boolean;
+ default "false";
+ description
+ "Enables segment-routing protocol extensions.";
+ }
+ container srgb {
+ description
+ "Global blocks to be advertised.";
+ must "./upper-bound > ./lower-bound";
+ leaf lower-bound {
+ type uint32;
+ default "16000";
+ description
+ "Lower value in the label range.";
+ }
+ leaf upper-bound {
+ type uint32;
+ default "23999";
+ description
+ "Upper value in the label range.";
+ }
+ }
+ container msd {
+ description
+ "MSD configuration.";
+ leaf node-msd {
+ type uint8;
+ description
+ "Node MSD is the lowest MSD supported by the node.";
+ }
+ }
+ container prefix-sid-map {
+ description
+ "Prefix SID configuration.";
+ list prefix-sid {
+ key "prefix";
+ unique "sid-value-type sid-value";
+ description
+ "List of prefix SID mapped to IPv4/IPv6
+ local prefixes.";
+ leaf prefix {
+ type inet:ip-prefix;
+ description
+ "Connected prefix sid.";
+ }
+ leaf sid-value-type {
+ type enumeration {
+ enum "index" {
+ value 0;
+ description
+ "The value will be interpreted as an index.";
+ }
+ enum "absolute" {
+ value 1;
+ description
+ "The value will become interpreted as an absolute
+ value.";
+ }
+ }
+ default "index";
+ description
+ "This leaf defines how value must be interpreted.";
+ }
+ leaf sid-value {
+ type uint32;
+ mandatory true;
+ description
+ "Value associated with prefix. The value must be
+ interpreted in the context of sid-value-type.";
+ }
+ leaf last-hop-behavior {
+ type enumeration {
+ enum "explicit-null" {
+ value 0;
+ description
+ "Use explicit-null for the SID.";
+ }
+ enum "no-php" {
+ value 1;
+ description
+ "Do not use Penultimate Hop Popping (PHP)
+ for the SID.";
+ }
+ enum "php" {
+ value 2;
+ description
+ "Use PHP for the SID.";
+ }
+ }
+ default "php";
+ description
+ "Configure last hop behavior.";
+ }
+ }
+ }
+ }
}
}
@@ -1172,6 +1298,16 @@ module frr-isisd {
description
"IS-IS interface parameters.";
uses interface-config;
+ }
+ }
+
+ augment "/frr-interface:lib/frr-interface:interface/frr-interface:state" {
+ description
+ "Extends interface model with IS-IS operational data.";
+ container isis {
+ presence "Present if an IS-IS circuit is defined for this interface.";
+ description
+ "IS-IS interface operational data.";
uses interface-state;
}
diff --git a/yang/frr-module-translator.yang b/yang/frr-module-translator.yang
index 6713eae76e..90d3cc8601 100644
--- a/yang/frr-module-translator.yang
+++ b/yang/frr-module-translator.yang
@@ -9,7 +9,32 @@ module frr-module-translator {
"FRR Users List: <mailto:frog@lists.frrouting.org>
FRR Development List: <mailto:dev@lists.frrouting.org>";
description
- "A model for FRR YANG module translators.";
+ "A model for FRR YANG module translators.
+
+ Copyright 2020 FRRouting
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";
revision 2018-07-31 {
description
diff --git a/yang/frr-nexthop.yang b/yang/frr-nexthop.yang
index 07e15eb774..ce6f21a663 100644
--- a/yang/frr-nexthop.yang
+++ b/yang/frr-nexthop.yang
@@ -25,7 +25,32 @@ module frr-nexthop {
"FRR Users List: <mailto:frog@lists.frrouting.org>
FRR Development List: <mailto:dev@lists.frrouting.org>";
description
- "This module defines a model for managing FRR nexthop information.";
+ "This module defines a model for managing FRR nexthop information.
+
+ Copyright 2020 FRRouting
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";
revision 2019-08-15 {
description
diff --git a/yang/frr-pim-rp.yang b/yang/frr-pim-rp.yang
index fb0a5aa209..a2eca5100a 100644
--- a/yang/frr-pim-rp.yang
+++ b/yang/frr-pim-rp.yang
@@ -29,7 +29,32 @@ module frr-pim-rp {
description
"The module defines a collection of YANG definitions common for
- all PIM (Protocol Independent Multicast) RP (Rendezvous Point) model.";
+ all PIM (Protocol Independent Multicast) RP (Rendezvous Point) model.
+
+ Copyright 2020 FRRouting
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";
revision 2017-03-09 {
description
diff --git a/yang/frr-pim.yang b/yang/frr-pim.yang
index 3b2ebdf6d3..2135d22f67 100644
--- a/yang/frr-pim.yang
+++ b/yang/frr-pim.yang
@@ -29,7 +29,32 @@ module frr-pim {
description
"The module defines a collection of YANG definitions common for
- PIM (Protocol Independent Multicast) model.";
+ PIM (Protocol Independent Multicast) model.
+
+ Copyright 2020 FRRouting
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";
revision 2017-03-09 {
description
diff --git a/yang/frr-ripd.yang b/yang/frr-ripd.yang
index 12c72b39b5..4e5795b8f7 100644
--- a/yang/frr-ripd.yang
+++ b/yang/frr-ripd.yang
@@ -22,7 +22,32 @@ module frr-ripd {
"FRR Users List: <mailto:frog@lists.frrouting.org>
FRR Development List: <mailto:dev@lists.frrouting.org>";
description
- "This module defines a model for managing FRR ripd daemon.";
+ "This module defines a model for managing FRR ripd daemon.
+
+ Copyright 2020 FRRouting
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";
revision 2019-09-09 {
description
diff --git a/yang/frr-ripngd.yang b/yang/frr-ripngd.yang
index c58962f5cd..47ae67b238 100644
--- a/yang/frr-ripngd.yang
+++ b/yang/frr-ripngd.yang
@@ -22,7 +22,32 @@ module frr-ripngd {
"FRR Users List: <mailto:frog@lists.frrouting.org>
FRR Development List: <mailto:dev@lists.frrouting.org>";
description
- "This module defines a model for managing FRR ripngd daemon.";
+ "This module defines a model for managing FRR ripngd daemon.
+
+ Copyright 2020 FRRouting
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";
revision 2019-09-09 {
description
diff --git a/yang/frr-route-map.yang b/yang/frr-route-map.yang
index 106593d9d3..f35a2976d1 100644
--- a/yang/frr-route-map.yang
+++ b/yang/frr-route-map.yang
@@ -17,7 +17,33 @@ module frr-route-map {
contact
"FRR Users List: <mailto:frog@lists.frrouting.org>
FRR Development List: <mailto:dev@lists.frrouting.org>";
- description "This module defines route map settings";
+ description
+ "This module defines route map settings
+
+ Copyright 2020 FRRouting
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";
revision 2019-07-01 {
description "Initial revision";
diff --git a/yang/frr-route-types.yang b/yang/frr-route-types.yang
index 8fdd10121e..057c32a7e7 100644
--- a/yang/frr-route-types.yang
+++ b/yang/frr-route-types.yang
@@ -9,7 +9,32 @@ module frr-route-types {
"FRR Users List: <mailto:frog@lists.frrouting.org>
FRR Development List: <mailto:dev@lists.frrouting.org>";
description
- "This module defines typedefs for route types.";
+ "This module defines typedefs for route types.
+
+ Copyright 2020 FRRouting
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";
revision 2018-03-28 {
description
diff --git a/yang/frr-routing.yang b/yang/frr-routing.yang
index ff84954aaf..5a06e597e5 100644
--- a/yang/frr-routing.yang
+++ b/yang/frr-routing.yang
@@ -20,7 +20,32 @@ module frr-routing {
description
"This YANG module defines essential components for the management
- of a routing subsystem.";
+ of a routing subsystem.
+
+ Copyright 2020 FRRouting
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";
revision 2019-08-15 {
description
diff --git a/yang/frr-staticd.yang b/yang/frr-staticd.yang
index ce8d641de1..f59158a0fd 100644
--- a/yang/frr-staticd.yang
+++ b/yang/frr-staticd.yang
@@ -26,7 +26,32 @@ module frr-staticd {
description
"This module defines a model for managing FRR staticd information.
This YANG module augments the ietf-routing with additional
- nexthop information";
+ nexthop information
+
+ Copyright 2020 FRRouting
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";
revision 2019-12-03 {
description
diff --git a/yang/frr-test-module.yang b/yang/frr-test-module.yang
index d85b12ea06..61915b1349 100644
--- a/yang/frr-test-module.yang
+++ b/yang/frr-test-module.yang
@@ -13,6 +13,34 @@ module frr-test-module {
prefix frr-interface;
}
+ description
+ "FRRouting internal testing module.
+
+ Copyright 2020 FRRouting
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";
+
revision 2018-11-26 {
description
"Initial revision.";
diff --git a/yang/frr-vrf.yang b/yang/frr-vrf.yang
index 4924a86e89..bb17bfaddb 100644
--- a/yang/frr-vrf.yang
+++ b/yang/frr-vrf.yang
@@ -9,7 +9,32 @@ module frr-vrf {
"FRR Users List: <mailto:frog@lists.frrouting.org>
FRR Development List: <mailto:dev@lists.frrouting.org>";
description
- "This module defines a model for managing FRR VRF.";
+ "This module defines a model for managing FRR VRF.
+
+ Copyright 2020 FRRouting
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";
revision 2019-12-06 {
description
diff --git a/yang/frr-vrrpd.yang b/yang/frr-vrrpd.yang
index 145387c4b4..c99d6d9877 100644
--- a/yang/frr-vrrpd.yang
+++ b/yang/frr-vrrpd.yang
@@ -21,7 +21,32 @@ module frr-vrrpd {
"FRR Users List: <mailto:frog@lists.frrouting.org>
FRR Development List: <mailto:dev@lists.frrouting.org>";
description
- "This module defines a model for managing FRR vrrpd daemon.";
+ "This module defines a model for managing FRR vrrpd daemon.
+
+ Copyright 2020 FRRouting
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";
revision 2019-09-09 {
description
diff --git a/yang/frr-zebra.yang b/yang/frr-zebra.yang
index 26e30b5fa9..4aeba14129 100644
--- a/yang/frr-zebra.yang
+++ b/yang/frr-zebra.yang
@@ -45,7 +45,32 @@ module frr-zebra {
"FRR Users List: <mailto:frog@lists.frrouting.org>
FRR Development List: <mailto:dev@lists.frrouting.org>";
description
- "This module defines a model for managing the FRR zebra daemon.";
+ "This module defines a model for managing the FRR zebra daemon.
+
+ Copyright 2020 FRRouting
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.";
revision 2019-06-01 {
description
@@ -607,45 +632,44 @@ module frr-zebra {
"RIBs supported by FRR.";
list rib {
key "afi-safi-name table-id";
- leaf table-id {
- type uint32;
- description
- "Routing Table id (default id - 254).";
- }
-
leaf afi-safi-name {
type identityref {
base afi-safi-type;
}
- mandatory true;
description
"AFI, SAFI name.";
}
+ leaf table-id {
+ type uint32;
+ description
+ "Routing Table id (default id - 254).";
+ }
+
list route {
key "prefix";
config false;
leaf prefix {
- type inet:ip-prefix;
- description
- "The route's prefix.";
+ type inet:ip-prefix;
+ description
+ "The route's prefix.";
}
+
list route-entry {
key "protocol";
leaf protocol {
- type frr-route-types:frr-route-types-v4;
- //TODO: Use unified route types done in PR 5183 when it is merged.
- //type frr-route-types:frr-route-types;
- description
- "The protocol owning the route.";
+ type frr-route-types:frr-route-types;
+ description
+ "The protocol owning the route.";
}
leaf instance {
type uint16;
must "../protocol = \"ospf\"";
description
- "Retrieve routes from a specific OSPF instance.";
+ "Retrieve routes from a specific OSPF instance.";
}
+
uses route-common;
}
}
@@ -2045,10 +2069,12 @@ module frr-zebra {
augment "/frr-vrf:lib/frr-vrf:vrf" {
description
"Extends VRF model with Zebra-related parameters.";
- uses ribs;
+ container zebra {
+ uses ribs;
+ }
}
- augment "/frr-vrf:lib/frr-vrf:vrf/ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop" {
+ augment "/frr-vrf:lib/frr-vrf:vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop" {
uses frr-nh:frr-nexthop-operational;
}
diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c
index 32b7faaad7..88d5ab5cec 100644
--- a/zebra/dplane_fpm_nl.c
+++ b/zebra/dplane_fpm_nl.c
@@ -74,6 +74,7 @@ struct fpm_nl_ctx {
bool connecting;
bool rib_complete;
bool rmac_complete;
+ bool use_nhg;
struct sockaddr_storage addr;
/* data plane buffers. */
@@ -99,6 +100,8 @@ struct fpm_nl_ctx {
struct thread *t_dequeue;
/* zebra events. */
+ struct thread *t_nhgreset;
+ struct thread *t_nhgwalk;
struct thread *t_ribreset;
struct thread *t_ribwalk;
struct thread *t_rmacreset;
@@ -144,6 +147,8 @@ enum fpm_nl_events {
FNE_DISABLE,
/* Reset counters. */
FNE_RESET_COUNTERS,
+ /* Toggle next hop group feature. */
+ FNE_TOGGLE_NHG,
};
/*
@@ -151,6 +156,8 @@ enum fpm_nl_events {
*/
static int fpm_process_event(struct thread *t);
static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx);
+static int fpm_nhg_send(struct thread *t);
+static int fpm_nhg_reset(struct thread *t);
static int fpm_rib_send(struct thread *t);
static int fpm_rib_reset(struct thread *t);
static int fpm_rmac_send(struct thread *t);
@@ -255,6 +262,37 @@ DEFUN(no_fpm_set_address, no_fpm_set_address_cmd,
return CMD_SUCCESS;
}
+DEFUN(fpm_use_nhg, fpm_use_nhg_cmd,
+ "fpm use-next-hop-groups",
+ FPM_STR
+ "Use netlink next hop groups feature.\n")
+{
+ /* Already enabled. */
+ if (gfnc->use_nhg)
+ return CMD_SUCCESS;
+
+ thread_add_event(gfnc->fthread->master, fpm_process_event, gfnc,
+ FNE_TOGGLE_NHG, &gfnc->t_event);
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(no_fpm_use_nhg, no_fpm_use_nhg_cmd,
+ "no fpm use-next-hop-groups",
+ NO_STR
+ FPM_STR
+ "Use netlink next hop groups feature.\n")
+{
+ /* Already disabled. */
+ if (!gfnc->use_nhg)
+ return CMD_SUCCESS;
+
+ thread_add_event(gfnc->fthread->master, fpm_process_event, gfnc,
+ FNE_TOGGLE_NHG, &gfnc->t_event);
+
+ return CMD_SUCCESS;
+}
+
DEFUN(fpm_reset_counters, fpm_reset_counters_cmd,
"clear fpm counters",
CLEAR_STR
@@ -368,6 +406,11 @@ static int fpm_write_config(struct vty *vty)
break;
}
+ if (!gfnc->use_nhg) {
+ vty_out(vty, "no fpm use-next-hop-groups\n");
+ written = 1;
+ }
+
return written;
}
@@ -399,14 +442,12 @@ static void fpm_reconnect(struct fpm_nl_ctx *fnc)
THREAD_OFF(fnc->t_read);
THREAD_OFF(fnc->t_write);
- if (fnc->t_ribreset)
- thread_cancel_async(zrouter.master, &fnc->t_ribreset, NULL);
- if (fnc->t_ribwalk)
- thread_cancel_async(zrouter.master, &fnc->t_ribwalk, NULL);
- if (fnc->t_rmacreset)
- thread_cancel_async(zrouter.master, &fnc->t_rmacreset, NULL);
- if (fnc->t_rmacwalk)
- thread_cancel_async(zrouter.master, &fnc->t_rmacwalk, NULL);
+ thread_cancel_async(zrouter.master, &fnc->t_nhgreset, NULL);
+ thread_cancel_async(zrouter.master, &fnc->t_nhgwalk, NULL);
+ thread_cancel_async(zrouter.master, &fnc->t_ribreset, NULL);
+ thread_cancel_async(zrouter.master, &fnc->t_ribwalk, NULL);
+ thread_cancel_async(zrouter.master, &fnc->t_rmacreset, NULL);
+ thread_cancel_async(zrouter.master, &fnc->t_rmacwalk, NULL);
/* FPM is disabled, don't attempt to connect. */
if (fnc->disabled)
@@ -490,9 +531,25 @@ static int fpm_write(struct thread *t)
fnc->connecting = false;
- /* Ask zebra main thread to start walking the RIB table. */
- thread_add_timer(zrouter.master, fpm_rib_send, fnc, 0,
- &fnc->t_ribwalk);
+ /*
+ * Walk the route tables to send old information before starting
+ * to send updated information.
+ *
+ * NOTE 1:
+ * RIB table walk is called after the next group table walk
+ * ends.
+ *
+ * NOTE 2:
+ * Don't attempt to go through next hop group table if we were
+ * explictly told to not use it.
+ */
+ if (fnc->use_nhg)
+ thread_add_timer(zrouter.master, fpm_nhg_send, fnc, 0,
+ &fnc->t_nhgwalk);
+ else
+ thread_add_timer(zrouter.master, fpm_rib_send, fnc, 0,
+ &fnc->t_ribwalk);
+
thread_add_timer(zrouter.master, fpm_rmac_send, fnc, 0,
&fnc->t_rmacwalk);
}
@@ -610,6 +667,8 @@ static int fpm_connect(struct thread *t)
&fnc->t_write);
/* Mark all routes as unsent. */
+ thread_add_timer(zrouter.master, fpm_nhg_reset, fnc, 0,
+ &fnc->t_nhgreset);
thread_add_timer(zrouter.master, fpm_rib_reset, fnc, 0,
&fnc->t_ribreset);
thread_add_timer(zrouter.master, fpm_rmac_reset, fnc, 0,
@@ -632,16 +691,27 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx)
size_t nl_buf_len;
ssize_t rv;
uint64_t obytes, obytes_peak;
+ enum dplane_op_e op = dplane_ctx_get_op(ctx);
+
+ /*
+ * If we were configured to not use next hop groups, then quit as soon
+ * as possible.
+ */
+ if ((!fnc->use_nhg)
+ && (op == DPLANE_OP_NH_DELETE || op == DPLANE_OP_NH_INSTALL
+ || op == DPLANE_OP_NH_UPDATE))
+ return 0;
nl_buf_len = 0;
frr_mutex_lock_autounlock(&fnc->obuf_mutex);
- switch (dplane_ctx_get_op(ctx)) {
+ switch (op) {
case DPLANE_OP_ROUTE_UPDATE:
case DPLANE_OP_ROUTE_DELETE:
rv = netlink_route_multipath(RTM_DELROUTE, ctx, nl_buf,
- sizeof(nl_buf), true);
+ sizeof(nl_buf), true,
+ fnc->use_nhg);
if (rv <= 0) {
zlog_err("%s: netlink_route_multipath failed",
__func__);
@@ -651,14 +721,14 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx)
nl_buf_len = (size_t)rv;
/* UPDATE operations need a INSTALL, otherwise just quit. */
- if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_DELETE)
+ if (op == DPLANE_OP_ROUTE_DELETE)
break;
/* FALL THROUGH */
case DPLANE_OP_ROUTE_INSTALL:
- rv = netlink_route_multipath(RTM_NEWROUTE, ctx,
- &nl_buf[nl_buf_len],
- sizeof(nl_buf) - nl_buf_len, true);
+ rv = netlink_route_multipath(
+ RTM_NEWROUTE, ctx, &nl_buf[nl_buf_len],
+ sizeof(nl_buf) - nl_buf_len, true, fnc->use_nhg);
if (rv <= 0) {
zlog_err("%s: netlink_route_multipath failed",
__func__);
@@ -680,9 +750,28 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx)
nl_buf_len = (size_t)rv;
break;
+ case DPLANE_OP_NH_DELETE:
+ rv = netlink_nexthop_encode(RTM_DELNEXTHOP, ctx, nl_buf,
+ sizeof(nl_buf));
+ if (rv <= 0) {
+ zlog_err("%s: netlink_nexthop_encode failed", __func__);
+ return 0;
+ }
+
+ nl_buf_len = (size_t)rv;
+ break;
case DPLANE_OP_NH_INSTALL:
case DPLANE_OP_NH_UPDATE:
- case DPLANE_OP_NH_DELETE:
+ rv = netlink_nexthop_encode(RTM_NEWNEXTHOP, ctx, nl_buf,
+ sizeof(nl_buf));
+ if (rv <= 0) {
+ zlog_err("%s: netlink_nexthop_encode failed", __func__);
+ return 0;
+ }
+
+ nl_buf_len = (size_t)rv;
+ break;
+
case DPLANE_OP_LSP_INSTALL:
case DPLANE_OP_LSP_UPDATE:
case DPLANE_OP_LSP_DELETE:
@@ -762,6 +851,65 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx)
return 0;
}
+/*
+ * Next hop walk/send functions.
+ */
+struct fpm_nhg_arg {
+ struct zebra_dplane_ctx *ctx;
+ struct fpm_nl_ctx *fnc;
+ bool complete;
+};
+
+static int fpm_nhg_send_cb(struct hash_bucket *bucket, void *arg)
+{
+ struct nhg_hash_entry *nhe = bucket->data;
+ struct fpm_nhg_arg *fna = arg;
+
+ /* This entry was already sent, skip it. */
+ if (CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_FPM))
+ return HASHWALK_CONTINUE;
+
+ /* Reset ctx to reuse allocated memory, take a snapshot and send it. */
+ dplane_ctx_reset(fna->ctx);
+ dplane_ctx_nexthop_init(fna->ctx, DPLANE_OP_NH_INSTALL, nhe);
+ if (fpm_nl_enqueue(fna->fnc, fna->ctx) == -1) {
+ /* Our buffers are full, lets give it some cycles. */
+ fna->complete = false;
+ return HASHWALK_ABORT;
+ }
+
+ /* Mark group as sent, so it doesn't get sent again. */
+ SET_FLAG(nhe->flags, NEXTHOP_GROUP_FPM);
+
+ return HASHWALK_CONTINUE;
+}
+
+static int fpm_nhg_send(struct thread *t)
+{
+ struct fpm_nl_ctx *fnc = THREAD_ARG(t);
+ struct fpm_nhg_arg fna;
+
+ fna.fnc = fnc;
+ fna.ctx = dplane_ctx_alloc();
+ fna.complete = true;
+
+ /* Send next hops. */
+ hash_walk(zrouter.nhgs_id, fpm_nhg_send_cb, &fna);
+
+ /* `free()` allocated memory. */
+ dplane_ctx_fini(&fna.ctx);
+
+ /* We are done sending next hops, lets install the routes now. */
+ if (fna.complete)
+ thread_add_timer(zrouter.master, fpm_rib_send, fnc, 0,
+ &fnc->t_ribwalk);
+ else /* Otherwise reschedule next hop group again. */
+ thread_add_timer(zrouter.master, fpm_nhg_send, fnc, 0,
+ &fnc->t_nhgwalk);
+
+ return 0;
+}
+
/**
* Send all RIB installed routes to the connected data plane.
*/
@@ -876,6 +1024,23 @@ static int fpm_rmac_send(struct thread *t)
return 0;
}
+/*
+ * Resets the next hop FPM flags so we send all next hops again.
+ */
+static void fpm_nhg_reset_cb(struct hash_bucket *bucket, void *arg)
+{
+ struct nhg_hash_entry *nhe = bucket->data;
+
+ /* Unset FPM installation flag so it gets installed again. */
+ UNSET_FLAG(nhe->flags, NEXTHOP_GROUP_FPM);
+}
+
+static int fpm_nhg_reset(struct thread *t)
+{
+ hash_iterate(zrouter.nhgs_id, fpm_nhg_reset_cb, NULL);
+ return 0;
+}
+
/**
* Resets the RIB FPM flags so we send all routes again.
*/
@@ -999,6 +1164,12 @@ static int fpm_process_event(struct thread *t)
memset(&fnc->counters, 0, sizeof(fnc->counters));
break;
+ case FNE_TOGGLE_NHG:
+ zlog_info("%s: toggle next hop groups support", __func__);
+ fnc->use_nhg = !fnc->use_nhg;
+ fpm_reconnect(fnc);
+ break;
+
default:
if (IS_ZEBRA_DEBUG_FPM)
zlog_debug("%s: unhandled event %d", __func__, event);
@@ -1027,12 +1198,17 @@ static int fpm_nl_start(struct zebra_dplane_provider *prov)
TAILQ_INIT(&fnc->ctxqueue);
pthread_mutex_init(&fnc->ctxqueue_mutex, NULL);
+ /* Set default values. */
+ fnc->use_nhg = true;
+
return 0;
}
static int fpm_nl_finish_early(struct fpm_nl_ctx *fnc)
{
/* Disable all events and close socket. */
+ THREAD_OFF(fnc->t_nhgreset);
+ THREAD_OFF(fnc->t_nhgwalk);
THREAD_OFF(fnc->t_ribreset);
THREAD_OFF(fnc->t_ribwalk);
THREAD_OFF(fnc->t_rmacreset);
@@ -1147,6 +1323,8 @@ static int fpm_nl_new(struct thread_master *tm)
install_element(ENABLE_NODE, &fpm_reset_counters_cmd);
install_element(CONFIG_NODE, &fpm_set_address_cmd);
install_element(CONFIG_NODE, &no_fpm_set_address_cmd);
+ install_element(CONFIG_NODE, &fpm_use_nhg_cmd);
+ install_element(CONFIG_NODE, &no_fpm_use_nhg_cmd);
return 0;
}
diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c
index 429bb968a5..c743011224 100644
--- a/zebra/if_netlink.c
+++ b/zebra/if_netlink.c
@@ -482,6 +482,7 @@ static int netlink_extract_vxlan_info(struct rtattr *link_data,
struct rtattr *attr[IFLA_VXLAN_MAX + 1];
vni_t vni_in_msg;
struct in_addr vtep_ip_in_msg;
+ ifindex_t ifindex_link;
memset(vxl_info, 0, sizeof(*vxl_info));
memset(attr, 0, sizeof(attr));
@@ -510,6 +511,15 @@ static int netlink_extract_vxlan_info(struct rtattr *link_data,
*(struct in_addr *)RTA_DATA(attr[IFLA_VXLAN_GROUP]);
}
+ if (!attr[IFLA_VXLAN_LINK]) {
+ if (IS_ZEBRA_DEBUG_KERNEL)
+ zlog_debug("IFLA_VXLAN_LINK missing "
+ "from VXLAN IF message");
+ } else {
+ ifindex_link =
+ *(ifindex_t *)RTA_DATA(attr[IFLA_VXLAN_LINK]);
+ vxl_info->ifindex_link = ifindex_link;
+ }
return 0;
}
@@ -519,7 +529,8 @@ static int netlink_extract_vxlan_info(struct rtattr *link_data,
* its members. Likewise, for VxLAN interface.
*/
static void netlink_interface_update_l2info(struct interface *ifp,
- struct rtattr *link_data, int add)
+ struct rtattr *link_data, int add,
+ ns_id_t link_nsid)
{
if (!link_data)
return;
@@ -538,7 +549,12 @@ static void netlink_interface_update_l2info(struct interface *ifp,
struct zebra_l2info_vxlan vxlan_info;
netlink_extract_vxlan_info(link_data, &vxlan_info);
+ vxlan_info.link_nsid = link_nsid;
zebra_l2_vxlanif_add_update(ifp, &vxlan_info, add);
+ if (link_nsid != NS_UNKNOWN &&
+ vxlan_info.ifindex_link)
+ zebra_if_update_link(ifp, vxlan_info.ifindex_link,
+ link_nsid);
}
}
@@ -622,6 +638,7 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup)
ifindex_t link_ifindex = IFINDEX_INTERNAL;
ifindex_t bond_ifindex = IFINDEX_INTERNAL;
struct zebra_if *zif;
+ ns_id_t link_nsid = ns_id;
zns = zebra_ns_lookup(ns_id);
ifi = NLMSG_DATA(h);
@@ -705,17 +722,20 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup)
if (tb[IFLA_LINK])
link_ifindex = *(ifindex_t *)RTA_DATA(tb[IFLA_LINK]);
+ if (tb[IFLA_LINK_NETNSID]) {
+ link_nsid = *(ns_id_t *)RTA_DATA(tb[IFLA_LINK_NETNSID]);
+ link_nsid = ns_id_get_absolute(ns_id, link_nsid);
+ }
+
/* Add interface.
* We add by index first because in some cases such as the master
* interface, we have the index before we have the name. Fixing
* back references on the slave interfaces is painful if not done
* this way, i.e. by creating by ifindex.
*/
- ifp = if_get_by_ifindex(ifi->ifi_index, vrf_id);
+ ifp = if_get_by_ifindex(ifi->ifi_index, vrf_id, name);
set_ifindex(ifp, ifi->ifi_index, zns); /* add it to ns struct */
- if_set_name(ifp, name);
-
ifp->flags = ifi->ifi_flags & 0x0000fffff;
ifp->mtu6 = ifp->mtu = *(uint32_t *)RTA_DATA(tb[IFLA_MTU]);
ifp->metric = 0;
@@ -749,9 +769,10 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup)
/* Extract and save L2 interface information, take additional actions.
*/
- netlink_interface_update_l2info(ifp, linkinfo[IFLA_INFO_DATA], 1);
+ netlink_interface_update_l2info(ifp, linkinfo[IFLA_INFO_DATA],
+ 1, link_nsid);
if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp))
- zebra_l2if_update_bridge_slave(ifp, bridge_ifindex);
+ zebra_l2if_update_bridge_slave(ifp, bridge_ifindex, ns_id);
else if (IS_ZEBRA_IF_BOND_SLAVE(ifp))
zebra_l2if_update_bond_slave(ifp, bond_ifindex);
@@ -1168,6 +1189,7 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
ifindex_t link_ifindex = IFINDEX_INTERNAL;
uint8_t old_hw_addr[INTERFACE_HWADDR_MAX];
struct zebra_if *zif;
+ ns_id_t link_nsid = ns_id;
zns = zebra_ns_lookup(ns_id);
ifi = NLMSG_DATA(h);
@@ -1235,6 +1257,10 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
if (tb[IFLA_LINK])
link_ifindex = *(ifindex_t *)RTA_DATA(tb[IFLA_LINK]);
+ if (tb[IFLA_LINK_NETNSID]) {
+ link_nsid = *(ns_id_t *)RTA_DATA(tb[IFLA_LINK_NETNSID]);
+ link_nsid = ns_id_get_absolute(ns_id, link_nsid);
+ }
if (tb[IFLA_IFALIAS]) {
desc = (char *)RTA_DATA(tb[IFLA_IFALIAS]);
}
@@ -1319,10 +1345,12 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
/* Extract and save L2 interface information, take
* additional actions. */
netlink_interface_update_l2info(
- ifp, linkinfo[IFLA_INFO_DATA], 1);
+ ifp, linkinfo[IFLA_INFO_DATA],
+ 1, link_nsid);
if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp))
zebra_l2if_update_bridge_slave(ifp,
- bridge_ifindex);
+ bridge_ifindex,
+ ns_id);
else if (IS_ZEBRA_IF_BOND_SLAVE(ifp))
zebra_l2if_update_bond_slave(ifp, bond_ifindex);
} else if (ifp->vrf_id != vrf_id) {
@@ -1421,10 +1449,12 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
/* Extract and save L2 interface information, take
* additional actions. */
netlink_interface_update_l2info(
- ifp, linkinfo[IFLA_INFO_DATA], 0);
+ ifp, linkinfo[IFLA_INFO_DATA],
+ 0, link_nsid);
if (IS_ZEBRA_IF_BRIDGE_SLAVE(ifp) || was_bridge_slave)
zebra_l2if_update_bridge_slave(ifp,
- bridge_ifindex);
+ bridge_ifindex,
+ ns_id);
else if (IS_ZEBRA_IF_BOND_SLAVE(ifp) || was_bond_slave)
zebra_l2if_update_bond_slave(ifp, bond_ifindex);
}
diff --git a/zebra/interface.c b/zebra/interface.c
index 9a248ba5d1..9d1f70609b 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -1236,6 +1236,23 @@ static void nbr_connected_dump_vty(struct vty *vty,
vty_out(vty, "\n");
}
+static const char *zebra_zifslavetype_2str(zebra_slave_iftype_t zif_slave_type)
+{
+ switch (zif_slave_type) {
+ case ZEBRA_IF_SLAVE_BRIDGE:
+ return "Bridge";
+ case ZEBRA_IF_SLAVE_VRF:
+ return "Vrf";
+ case ZEBRA_IF_SLAVE_BOND:
+ return "Bond";
+ case ZEBRA_IF_SLAVE_OTHER:
+ return "Other";
+ case ZEBRA_IF_SLAVE_NONE:
+ return "None";
+ }
+ return "None";
+}
+
static const char *zebra_ziftype_2str(zebra_iftype_t zif_type)
{
switch (zif_type) {
@@ -1463,6 +1480,9 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp)
vty_out(vty, " Interface Type %s\n",
zebra_ziftype_2str(zebra_if->zif_type));
+ vty_out(vty, " Interface Slave Type %s\n",
+ zebra_zifslavetype_2str(zebra_if->zif_slave_type));
+
if (IS_ZEBRA_IF_BRIDGE(ifp)) {
struct zebra_l2info_bridge *bridge_info;
@@ -1488,6 +1508,17 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp)
if (vxlan_info->mcast_grp.s_addr != INADDR_ANY)
vty_out(vty, " Mcast Group %s",
inet_ntoa(vxlan_info->mcast_grp));
+ if (vxlan_info->ifindex_link &&
+ (vxlan_info->link_nsid != NS_UNKNOWN)) {
+ struct interface *ifp;
+
+ ifp = if_lookup_by_index_per_ns(
+ zebra_ns_lookup(vxlan_info->link_nsid),
+ vxlan_info->ifindex_link);
+ vty_out(vty, " Link Interface %s",
+ ifp == NULL ? "Unknown" :
+ ifp->name);
+ }
vty_out(vty, "\n");
}
diff --git a/zebra/main.c b/zebra/main.c
index e230a744f6..f447e9aa07 100644
--- a/zebra/main.c
+++ b/zebra/main.c
@@ -177,7 +177,7 @@ static void sigint(void)
vrf_terminate();
rtadv_terminate();
- ns_walk_func(zebra_ns_early_shutdown);
+ ns_walk_func(zebra_ns_early_shutdown, NULL, NULL);
zebra_ns_notify_close();
access_list_reset();
@@ -208,7 +208,7 @@ int zebra_finalize(struct thread *dummy)
zlog_info("Zebra final shutdown");
/* Final shutdown of ns resources */
- ns_walk_func(zebra_ns_final_shutdown);
+ ns_walk_func(zebra_ns_final_shutdown, NULL, NULL);
/* Stop dplane thread and finish any cleanup */
zebra_dplane_shutdown();
diff --git a/zebra/rib.h b/zebra/rib.h
index 3717a12814..a024b6dfaa 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -41,7 +41,7 @@
extern "C" {
#endif
-typedef enum { RNH_NEXTHOP_TYPE, RNH_IMPORT_CHECK_TYPE } rnh_type_t;
+enum rnh_type { RNH_NEXTHOP_TYPE, RNH_IMPORT_CHECK_TYPE };
PREDECL_LIST(rnh_list)
@@ -58,7 +58,7 @@ struct rnh {
afi_t afi;
- rnh_type_t type;
+ enum rnh_type type;
uint32_t seqno;
@@ -251,12 +251,22 @@ DECLARE_LIST(re_list, struct route_entry, next);
(re) && ((next) = re_list_next(&((dest)->routes), (re)), 1); \
(re) = (next))
+#define RE_DEST_FIRST_ROUTE(dest, re) \
+ ((re) = (dest) ? re_list_first(&((dest)->routes)) : NULL)
+
+#define RE_DEST_NEXT_ROUTE(dest, re) \
+ ((re) = (dest) ? re_list_next(&((dest)->routes), (re)) : NULL)
+
#define RNODE_FOREACH_RE(rn, re) \
RE_DEST_FOREACH_ROUTE (rib_dest_from_rnode(rn), re)
#define RNODE_FOREACH_RE_SAFE(rn, re, next) \
RE_DEST_FOREACH_ROUTE_SAFE (rib_dest_from_rnode(rn), re, next)
+#define RNODE_FIRST_RE(rn, re) RE_DEST_FIRST_ROUTE(rib_dest_from_rnode(rn), re)
+
+#define RNODE_NEXT_RE(rn, re) RE_DEST_NEXT_ROUTE(rib_dest_from_rnode(rn), re)
+
#if defined(HAVE_RTADV)
/* Structure which hold status of router advertisement. */
struct rtadv {
@@ -276,7 +286,7 @@ struct rtadv {
* Structure that is hung off of a route_table that holds information about
* the table.
*/
-typedef struct rib_table_info_t_ {
+struct rib_table_info {
/*
* Back pointer to zebra_vrf.
@@ -284,14 +294,13 @@ typedef struct rib_table_info_t_ {
struct zebra_vrf *zvrf;
afi_t afi;
safi_t safi;
+};
-} rib_table_info_t;
-
-typedef enum {
+enum rib_tables_iter_state {
RIB_TABLES_ITER_S_INIT,
RIB_TABLES_ITER_S_ITERATING,
RIB_TABLES_ITER_S_DONE
-} rib_tables_iter_state_t;
+};
/*
* Structure that holds state for iterating over all tables in the
@@ -301,20 +310,21 @@ typedef struct rib_tables_iter_t_ {
vrf_id_t vrf_id;
int afi_safi_ix;
- rib_tables_iter_state_t state;
+ enum rib_tables_iter_state state;
} rib_tables_iter_t;
/* Events/reasons triggering a RIB update. */
-typedef enum {
+enum rib_update_event {
RIB_UPDATE_KERNEL,
RIB_UPDATE_RMAP_CHANGE,
RIB_UPDATE_OTHER,
RIB_UPDATE_MAX
-} rib_update_event_t;
+};
extern void route_entry_copy_nexthops(struct route_entry *re,
struct nexthop *nh);
-int route_entry_update_nhe(struct route_entry *re, struct nhg_hash_entry *new);
+int route_entry_update_nhe(struct route_entry *re,
+ struct nhg_hash_entry *new_nhghe);
#define route_entry_dump(prefix, src, re) _route_entry_dump(__func__, prefix, src, re)
extern void _route_entry_dump(const char *func, union prefixconstptr pp,
@@ -374,10 +384,10 @@ extern struct route_entry *rib_match_ipv4_multicast(vrf_id_t vrf_id,
extern struct route_entry *rib_lookup_ipv4(struct prefix_ipv4 *p,
vrf_id_t vrf_id);
-extern void rib_update(rib_update_event_t event);
-extern void rib_update_vrf(vrf_id_t vrf_id, rib_update_event_t event);
+extern void rib_update(enum rib_update_event event);
+extern void rib_update_vrf(vrf_id_t vrf_id, enum rib_update_event event);
extern void rib_update_table(struct route_table *table,
- rib_update_event_t event);
+ enum rib_update_event event);
extern int rib_sweep_route(struct thread *t);
extern void rib_sweep_table(struct route_table *table);
extern void rib_close_table(struct route_table *table);
@@ -412,9 +422,9 @@ extern void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq);
/*
* rib_table_info
*/
-static inline rib_table_info_t *rib_table_info(struct route_table *table)
+static inline struct rib_table_info *rib_table_info(struct route_table *table)
{
- return (rib_table_info_t *)route_table_get_info(table);
+ return (struct rib_table_info *)route_table_get_info(table);
}
/*
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index 466e985494..2e6cc7cd06 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -1552,7 +1552,8 @@ static void netlink_route_nexthop_encap(struct nlmsghdr *n, size_t nlen,
* Routing table change via netlink interface, using a dataplane context object
*/
ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx,
- uint8_t *data, size_t datalen, bool fpm)
+ uint8_t *data, size_t datalen, bool fpm,
+ bool force_nhg)
{
int bytelen;
struct nexthop *nexthop = NULL;
@@ -1674,7 +1675,7 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx,
RTA_PAYLOAD(rta));
}
- if (kernel_nexthops_supported()) {
+ if (kernel_nexthops_supported() || force_nhg) {
/* Kernel supports nexthop objects */
if (IS_ZEBRA_DEBUG_KERNEL)
zlog_debug(
@@ -1954,43 +1955,42 @@ static void _netlink_nexthop_build_group(struct nlmsghdr *n, size_t req_size,
}
/**
- * netlink_nexthop() - Nexthop change via the netlink interface
+ * Next hop packet encoding helper function.
*
- * @ctx: Dataplane ctx
+ * \param[in] cmd netlink command.
+ * \param[in] ctx dataplane context (information snapshot).
+ * \param[out] buf buffer to hold the packet.
+ * \param[in] buflen amount of buffer bytes.
*
- * Return: Result status
+ * \returns -1 on failure or the number of bytes written to buf.
*/
-static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx)
+ssize_t netlink_nexthop_encode(uint16_t cmd, const struct zebra_dplane_ctx *ctx,
+ void *buf, size_t buflen)
{
struct {
struct nlmsghdr n;
struct nhmsg nhm;
- char buf[NL_PKT_BUF_SIZE];
- } req;
+ char buf[];
+ } *req = buf;
mpls_lse_t out_lse[MPLS_MAX_LABELS];
char label_buf[256];
int num_labels = 0;
- size_t req_size = sizeof(req);
-
- /* Nothing to do if the kernel doesn't support nexthop objects */
- if (!kernel_nexthops_supported())
- return 0;
label_buf[0] = '\0';
- memset(&req, 0, req_size);
+ memset(req, 0, buflen);
- req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg));
- req.n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
+ req->n.nlmsg_len = NLMSG_LENGTH(sizeof(struct nhmsg));
+ req->n.nlmsg_flags = NLM_F_CREATE | NLM_F_REQUEST;
if (cmd == RTM_NEWNEXTHOP)
- req.n.nlmsg_flags |= NLM_F_REPLACE;
+ req->n.nlmsg_flags |= NLM_F_REPLACE;
- req.n.nlmsg_type = cmd;
- req.n.nlmsg_pid = dplane_ctx_get_ns(ctx)->nls.snl.nl_pid;
+ req->n.nlmsg_type = cmd;
+ req->n.nlmsg_pid = dplane_ctx_get_ns(ctx)->nls.snl.nl_pid;
- req.nhm.nh_family = AF_UNSPEC;
+ req->nhm.nh_family = AF_UNSPEC;
/* TODO: Scope? */
uint32_t id = dplane_ctx_get_nhe_id(ctx);
@@ -2002,7 +2002,7 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx)
return -1;
}
- addattr32(&req.n, req_size, NHA_ID, id);
+ addattr32(&req->n, buflen, NHA_ID, id);
if (cmd == RTM_NEWNEXTHOP) {
/*
@@ -2013,7 +2013,7 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx)
*/
if (dplane_ctx_get_nhe_nh_grp_count(ctx))
_netlink_nexthop_build_group(
- &req.n, req_size, id,
+ &req->n, buflen, id,
dplane_ctx_get_nhe_nh_grp(ctx),
dplane_ctx_get_nhe_nh_grp_count(ctx));
else {
@@ -2022,23 +2022,23 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx)
afi_t afi = dplane_ctx_get_nhe_afi(ctx);
if (afi == AFI_IP)
- req.nhm.nh_family = AF_INET;
+ req->nhm.nh_family = AF_INET;
else if (afi == AFI_IP6)
- req.nhm.nh_family = AF_INET6;
+ req->nhm.nh_family = AF_INET6;
switch (nh->type) {
case NEXTHOP_TYPE_IPV4:
case NEXTHOP_TYPE_IPV4_IFINDEX:
- addattr_l(&req.n, req_size, NHA_GATEWAY,
+ addattr_l(&req->n, buflen, NHA_GATEWAY,
&nh->gate.ipv4, IPV4_MAX_BYTELEN);
break;
case NEXTHOP_TYPE_IPV6:
case NEXTHOP_TYPE_IPV6_IFINDEX:
- addattr_l(&req.n, req_size, NHA_GATEWAY,
+ addattr_l(&req->n, buflen, NHA_GATEWAY,
&nh->gate.ipv6, IPV6_MAX_BYTELEN);
break;
case NEXTHOP_TYPE_BLACKHOLE:
- addattr_l(&req.n, req_size, NHA_BLACKHOLE, NULL,
+ addattr_l(&req->n, buflen, NHA_BLACKHOLE, NULL,
0);
/* Blackhole shouldn't have anymore attributes
*/
@@ -2055,10 +2055,10 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx)
return -1;
}
- addattr32(&req.n, req_size, NHA_OIF, nh->ifindex);
+ addattr32(&req->n, buflen, NHA_OIF, nh->ifindex);
if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_ONLINK))
- req.nhm.nh_flags |= RTNH_F_ONLINK;
+ req->nhm.nh_flags |= RTNH_F_ONLINK;
num_labels =
build_label_stack(nh->nh_label, out_lse,
@@ -2072,10 +2072,10 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx)
/*
* TODO: MPLS unsupported for now in kernel.
*/
- if (req.nhm.nh_family == AF_MPLS)
+ if (req->nhm.nh_family == AF_MPLS)
goto nexthop_done;
#if 0
- addattr_l(&req.n, req_size, NHA_NEWDST,
+ addattr_l(&req->n, buflen, NHA_NEWDST,
&out_lse,
num_labels
* sizeof(mpls_lse_t));
@@ -2084,16 +2084,16 @@ static int netlink_nexthop(int cmd, struct zebra_dplane_ctx *ctx)
struct rtattr *nest;
uint16_t encap = LWTUNNEL_ENCAP_MPLS;
- addattr_l(&req.n, req_size,
+ addattr_l(&req->n, buflen,
NHA_ENCAP_TYPE, &encap,
sizeof(uint16_t));
- nest = addattr_nest(&req.n, req_size,
+ nest = addattr_nest(&req->n, buflen,
NHA_ENCAP);
- addattr_l(&req.n, req_size,
+ addattr_l(&req->n, buflen,
MPLS_IPTUNNEL_DST, &out_lse,
num_labels
* sizeof(mpls_lse_t));
- addattr_nest_end(&req.n, nest);
+ addattr_nest_end(&req->n, nest);
}
}
@@ -2106,7 +2106,8 @@ nexthop_done:
nh->vrf_id, label_buf);
}
- req.nhm.nh_protocol = zebra2proto(dplane_ctx_get_nhe_type(ctx));
+ req->nhm.nh_protocol =
+ zebra2proto(dplane_ctx_get_nhe_type(ctx));
} else if (cmd != RTM_DELNEXTHOP) {
flog_err(
@@ -2120,8 +2121,7 @@ nexthop_done:
zlog_debug("%s: %s, id=%u", __func__, nl_msg_type_to_str(cmd),
id);
- return netlink_talk_info(netlink_talk_filter, &req.n,
- dplane_ctx_get_ns(ctx), 0);
+ return NLMSG_ALIGN(req->n.nlmsg_len);
}
/**
@@ -2136,6 +2136,7 @@ enum zebra_dplane_result kernel_nexthop_update(struct zebra_dplane_ctx *ctx)
enum dplane_op_e op;
int cmd = 0;
int ret = 0;
+ char buf[NL_PKT_BUF_SIZE];
op = dplane_ctx_get_op(ctx);
if (op == DPLANE_OP_NH_INSTALL || op == DPLANE_OP_NH_UPDATE)
@@ -2149,7 +2150,15 @@ enum zebra_dplane_result kernel_nexthop_update(struct zebra_dplane_ctx *ctx)
return ZEBRA_DPLANE_REQUEST_FAILURE;
}
- ret = netlink_nexthop(cmd, ctx);
+ /* Nothing to do if the kernel doesn't support nexthop objects */
+ if (!kernel_nexthops_supported())
+ return ZEBRA_DPLANE_REQUEST_SUCCESS;
+
+ if (netlink_nexthop_encode(cmd, ctx, buf, sizeof(buf)) > 0)
+ ret = netlink_talk_info(netlink_talk_filter, (void *)&buf,
+ dplane_ctx_get_ns(ctx), 0);
+ else
+ ret = 0;
return (ret == 0 ? ZEBRA_DPLANE_REQUEST_SUCCESS
: ZEBRA_DPLANE_REQUEST_FAILURE);
@@ -2188,7 +2197,7 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
!RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx))) {
netlink_route_multipath(RTM_DELROUTE, ctx,
nl_pkt, sizeof(nl_pkt),
- false);
+ false, false);
netlink_talk_info(netlink_talk_filter,
(struct nlmsghdr *)nl_pkt,
dplane_ctx_get_ns(ctx), 0);
@@ -2209,7 +2218,7 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
if (!RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx))) {
netlink_route_multipath(RTM_DELROUTE, ctx,
nl_pkt, sizeof(nl_pkt),
- false);
+ false, false);
netlink_talk_info(netlink_talk_filter,
(struct nlmsghdr *)nl_pkt,
dplane_ctx_get_ns(ctx), 0);
@@ -2222,7 +2231,7 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx)
}
if (!RSYSTEM_ROUTE(dplane_ctx_get_type(ctx))) {
- netlink_route_multipath(cmd, ctx, nl_pkt, sizeof(nl_pkt),
+ netlink_route_multipath(cmd, ctx, nl_pkt, sizeof(nl_pkt), false,
false);
ret = netlink_talk_info(netlink_talk_filter,
(struct nlmsghdr *)nl_pkt,
@@ -2552,10 +2561,15 @@ int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla,
/**
* netlink_update_neigh_ctx_internal() - Common helper api for evpn
* neighbor updates using dataplane context object.
+ * Here, a neighbor refers to a bridge forwarding database entry for
+ * either unicast forwarding or head-end replication or an IP neighbor
+ * entry.
* @ctx: Dataplane context
* @cmd: Netlink command (RTM_NEWNEIGH or RTM_DELNEIGH)
* @mac: A neighbor cache link layer address
* @ip: A neighbor cache n/w layer destination address
+ * In the case of bridge FDB, this represnts the remote
+ * VTEP IP.
* @replace_obj: Whether NEW request should replace existing object or
* add to the end of the list
* @family: AF_* netlink family
@@ -2975,7 +2989,6 @@ netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, uint8_t *data,
int cmd;
uint8_t flags;
uint16_t state;
- uint8_t nl_pkt[NL_PKT_BUF_SIZE];
cmd = dplane_ctx_get_op(ctx) == DPLANE_OP_MAC_INSTALL
? RTM_NEWNEIGH : RTM_DELNEIGH;
@@ -3014,9 +3027,8 @@ netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, uint8_t *data,
}
total = netlink_update_neigh_ctx_internal(
- ctx, cmd, dplane_ctx_mac_get_addr(ctx),
- dplane_ctx_neigh_get_ipaddr(ctx), true, AF_BRIDGE, 0,
- flags, state, nl_pkt, sizeof(nl_pkt));
+ ctx, cmd, dplane_ctx_mac_get_addr(ctx), &vtep_ip,
+ true, AF_BRIDGE, 0, flags, state, data, datalen);
return total;
}
diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h
index a364d305c5..c09609f47c 100644
--- a/zebra/rt_netlink.h
+++ b/zebra/rt_netlink.h
@@ -67,8 +67,8 @@ void rt_netlink_init(void);
extern int netlink_mpls_multipath(int cmd, struct zebra_dplane_ctx *ctx);
extern ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx,
- uint8_t *data, size_t datalen,
- bool fpm);
+ uint8_t *data, size_t datalen, bool fpm,
+ bool force_nhg);
extern ssize_t netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx,
uint8_t *data, size_t datalen);
@@ -78,6 +78,9 @@ extern int netlink_route_read(struct zebra_ns *zns);
extern int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id,
int startup);
extern int netlink_nexthop_read(struct zebra_ns *zns);
+extern ssize_t netlink_nexthop_encode(uint16_t cmd,
+ const struct zebra_dplane_ctx *ctx,
+ void *buf, size_t buflen);
extern int netlink_neigh_change(struct nlmsghdr *h, ns_id_t ns_id);
extern int netlink_macfdb_read(struct zebra_ns *zns);
diff --git a/zebra/rtadv.c b/zebra/rtadv.c
index 0fb3390410..fa0a682d07 100644
--- a/zebra/rtadv.c
+++ b/zebra/rtadv.c
@@ -46,14 +46,14 @@
#include "zebra/zebra_errors.h"
#include "zebra/zebra_router.h"
-#ifndef VTYSH_EXTRACT_PL
-#include "zebra/rtadv_clippy.c"
-#endif
-
extern struct zebra_privs_t zserv_privs;
#if defined(HAVE_RTADV)
+#ifndef VTYSH_EXTRACT_PL
+#include "zebra/rtadv_clippy.c"
+#endif
+
DEFINE_MTYPE_STATIC(ZEBRA, RTADV_PREFIX, "Router Advertisement Prefix")
#ifdef OPEN_BSD
@@ -171,7 +171,7 @@ static int rtadv_recv_packet(struct zebra_vrf *zvrf, int sock, uint8_t *buf,
/* Send router advertisement packet. */
static void rtadv_send_packet(int sock, struct interface *ifp,
- ipv6_nd_suppress_ra_status stop)
+ enum ipv6_nd_suppress_ra_status stop)
{
struct msghdr msg;
struct iovec iov;
@@ -1003,7 +1003,7 @@ void rtadv_delete_prefix(struct zebra_if *zif, const struct prefix *p)
}
static void ipv6_nd_suppress_ra_set(struct interface *ifp,
- ipv6_nd_suppress_ra_status status)
+ enum ipv6_nd_suppress_ra_status status)
{
struct zebra_if *zif;
struct zebra_vrf *zvrf;
@@ -2648,7 +2648,7 @@ void rtadv_init(struct zebra_vrf *zvrf)
{
/* Empty.*/;
}
-void rtadv_terminate(struct zebra_vrf *zvrf)
+void rtadv_terminate(void)
{
/* Empty.*/;
}
@@ -2677,4 +2677,28 @@ void rtadv_stop_ra_all(void)
/* Empty.*/;
}
+/*
+ * If the end user does not have RADV enabled we should
+ * handle this better
+ */
+void zebra_interface_radv_disable(ZAPI_HANDLER_ARGS)
+{
+ if (IS_ZEBRA_DEBUG_PACKET)
+ zlog_debug(
+ "Received %s command, but ZEBRA is not compiled with Router Advertisements on",
+ zserv_command_string(hdr->command));
+
+ return;
+}
+
+void zebra_interface_radv_enable(ZAPI_HANDLER_ARGS)
+{
+ if (IS_ZEBRA_DEBUG_PACKET)
+ zlog_debug(
+ "Received %s command, but ZEBRA is not compiled with Router Advertisements on",
+ zserv_command_string(hdr->command));
+
+ return;
+}
+
#endif /* HAVE_RTADV */
diff --git a/zebra/rtadv.h b/zebra/rtadv.h
index 68a5bbcdbe..d7a1ccfb29 100644
--- a/zebra/rtadv.h
+++ b/zebra/rtadv.h
@@ -147,10 +147,10 @@ enum ipv6_nd_prefix_source {
PREFIX_SRC_BOTH,
};
-typedef enum {
+enum ipv6_nd_suppress_ra_status {
RA_ENABLE = 0,
RA_SUPPRESS,
-} ipv6_nd_suppress_ra_status;
+};
extern void rtadv_init(struct zebra_vrf *zvrf);
extern void rtadv_vrf_terminate(struct zebra_vrf *zvrf);
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index 092b5dd3c2..ffe5ca4845 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -1451,10 +1451,6 @@ static struct nexthop *nexthop_from_zapi(struct route_entry *re,
&api_nh->gate.ipv4, NULL, api_nh->ifindex,
api_nh->vrf_id);
- ifp = if_lookup_by_index(api_nh->ifindex, api_nh->vrf_id);
- if (ifp && connected_is_unnumbered(ifp))
- SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK);
-
/* Special handling for IPv4 routes sourced from EVPN:
* the nexthop and associated MAC need to be installed.
*/
@@ -1516,8 +1512,16 @@ static struct nexthop *nexthop_from_zapi(struct route_entry *re,
goto done;
}
+ /* Mark nexthop as onlink either if client has explicitly told us
+ * to or if the nexthop is on an 'unnumbered' interface.
+ */
if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_ONLINK))
SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK);
+ else if (api_nh->type == NEXTHOP_TYPE_IPV4_IFINDEX) {
+ ifp = if_lookup_by_index(api_nh->ifindex, api_nh->vrf_id);
+ if (ifp && connected_is_unnumbered(ifp))
+ SET_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK);
+ }
if (CHECK_FLAG(api_nh->flags, ZAPI_NEXTHOP_FLAG_WEIGHT))
nexthop->weight = api_nh->weight;
@@ -2825,13 +2829,8 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = {
[ZEBRA_VRF_UNREGISTER] = zread_vrf_unregister,
[ZEBRA_VRF_LABEL] = zread_vrf_label,
[ZEBRA_BFD_CLIENT_REGISTER] = zebra_ptm_bfd_client_register,
-#if defined(HAVE_RTADV)
[ZEBRA_INTERFACE_ENABLE_RADV] = zebra_interface_radv_enable,
[ZEBRA_INTERFACE_DISABLE_RADV] = zebra_interface_radv_disable,
-#else
- [ZEBRA_INTERFACE_ENABLE_RADV] = NULL,
- [ZEBRA_INTERFACE_DISABLE_RADV] = NULL,
-#endif
[ZEBRA_MPLS_LABELS_ADD] = zread_mpls_labels_add,
[ZEBRA_MPLS_LABELS_DELETE] = zread_mpls_labels_delete,
[ZEBRA_MPLS_LABELS_REPLACE] = zread_mpls_labels_replace,
diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c
index 143354b166..278e894d06 100644
--- a/zebra/zebra_dplane.c
+++ b/zebra/zebra_dplane.c
@@ -1530,7 +1530,7 @@ int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
{
int ret = EINVAL;
const struct route_table *table = NULL;
- const rib_table_info_t *info;
+ const struct rib_table_info *info;
const struct prefix *p, *src_p;
struct zebra_ns *zns;
struct zebra_vrf *zvrf;
@@ -1658,9 +1658,8 @@ done:
*
* Return: Result status
*/
-static int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx,
- enum dplane_op_e op,
- struct nhg_hash_entry *nhe)
+int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
+ struct nhg_hash_entry *nhe)
{
struct zebra_vrf *zvrf = NULL;
struct zebra_ns *zns = NULL;
diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h
index f01ca2e84c..9ce542944d 100644
--- a/zebra/zebra_dplane.h
+++ b/zebra/zebra_dplane.h
@@ -499,6 +499,10 @@ enum zebra_dplane_result dplane_vtep_delete(const struct interface *ifp,
int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
struct route_node *rn, struct route_entry *re);
+/* Encode next hop information into data plane context. */
+int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op,
+ struct nhg_hash_entry *nhe);
+
/* Retrieve the limit on the number of pending, unprocessed updates. */
uint32_t dplane_get_in_queue_limit(void);
diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c
index 8f97c8cf47..47b4965396 100644
--- a/zebra/zebra_fpm.c
+++ b/zebra/zebra_fpm.c
@@ -76,15 +76,15 @@ static void zfpm_iterate_rmac_table(struct hash_bucket *backet, void *args);
* Structure that holds state for iterating over all route_node
* structures that are candidates for being communicated to the FPM.
*/
-typedef struct zfpm_rnodes_iter_t_ {
+struct zfpm_rnodes_iter {
rib_tables_iter_t tables_iter;
route_table_iter_t iter;
-} zfpm_rnodes_iter_t;
+};
/*
* Statistics.
*/
-typedef struct zfpm_stats_t_ {
+struct zfpm_stats {
unsigned long connect_calls;
unsigned long connect_no_sock;
@@ -115,13 +115,12 @@ typedef struct zfpm_stats_t_ {
unsigned long t_conn_up_yields;
unsigned long t_conn_up_aborts;
unsigned long t_conn_up_finishes;
-
-} zfpm_stats_t;
+};
/*
* States for the FPM state machine.
*/
-typedef enum {
+enum zfpm_state {
/*
* In this state we are not yet ready to connect to the FPM. This
@@ -147,20 +146,21 @@ typedef enum {
*/
ZFPM_STATE_ESTABLISHED
-} zfpm_state_t;
+};
/*
* Message format to be used to communicate with the FPM.
*/
-typedef enum {
+enum zfpm_msg_format {
ZFPM_MSG_FORMAT_NONE,
ZFPM_MSG_FORMAT_NETLINK,
ZFPM_MSG_FORMAT_PROTOBUF,
-} zfpm_msg_format_e;
+};
+
/*
* Globals.
*/
-typedef struct zfpm_glob_t_ {
+struct zfpm_glob {
/*
* True if the FPM module has been enabled.
@@ -170,11 +170,11 @@ typedef struct zfpm_glob_t_ {
/*
* Message format to be used to communicate with the fpm.
*/
- zfpm_msg_format_e message_format;
+ enum zfpm_msg_format message_format;
struct thread_master *master;
- zfpm_state_t state;
+ enum zfpm_state state;
in_addr_t fpm_server;
/*
@@ -231,7 +231,7 @@ typedef struct zfpm_glob_t_ {
struct thread *t_conn_down;
struct {
- zfpm_rnodes_iter_t iter;
+ struct zfpm_rnodes_iter iter;
} t_conn_down_state;
/*
@@ -241,7 +241,7 @@ typedef struct zfpm_glob_t_ {
struct thread *t_conn_up;
struct {
- zfpm_rnodes_iter_t iter;
+ struct zfpm_rnodes_iter iter;
} t_conn_up_state;
unsigned long connect_calls;
@@ -251,18 +251,18 @@ typedef struct zfpm_glob_t_ {
* Stats from the start of the current statistics interval up to
* now. These are the counters we typically update in the code.
*/
- zfpm_stats_t stats;
+ struct zfpm_stats stats;
/*
* Statistics that were gathered in the last collection interval.
*/
- zfpm_stats_t last_ivl_stats;
+ struct zfpm_stats last_ivl_stats;
/*
* Cumulative stats from the last clear to the start of the current
* statistics interval.
*/
- zfpm_stats_t cumulative_stats;
+ struct zfpm_stats cumulative_stats;
/*
* Stats interval timer.
@@ -273,18 +273,17 @@ typedef struct zfpm_glob_t_ {
* If non-zero, the last time when statistics were cleared.
*/
time_t last_stats_clear_time;
+};
-} zfpm_glob_t;
-
-static zfpm_glob_t zfpm_glob_space;
-static zfpm_glob_t *zfpm_g = &zfpm_glob_space;
+static struct zfpm_glob zfpm_glob_space;
+static struct zfpm_glob *zfpm_g = &zfpm_glob_space;
static int zfpm_trigger_update(struct route_node *rn, const char *reason);
static int zfpm_read_cb(struct thread *thread);
static int zfpm_write_cb(struct thread *thread);
-static void zfpm_set_state(zfpm_state_t state, const char *reason);
+static void zfpm_set_state(enum zfpm_state state, const char *reason);
static void zfpm_start_connect_timer(const char *reason);
static void zfpm_start_stats_timer(void);
static void zfpm_mac_info_del(struct fpm_mac_info_t *fpm_mac);
@@ -300,7 +299,7 @@ static inline int zfpm_thread_should_yield(struct thread *t)
/*
* zfpm_state_to_str
*/
-static const char *zfpm_state_to_str(zfpm_state_t state)
+static const char *zfpm_state_to_str(enum zfpm_state state)
{
switch (state) {
@@ -343,7 +342,7 @@ static time_t zfpm_get_elapsed_time(time_t reference)
/*
* zfpm_rnodes_iter_init
*/
-static inline void zfpm_rnodes_iter_init(zfpm_rnodes_iter_t *iter)
+static inline void zfpm_rnodes_iter_init(struct zfpm_rnodes_iter *iter)
{
memset(iter, 0, sizeof(*iter));
rib_tables_iter_init(&iter->tables_iter);
@@ -360,7 +359,8 @@ static inline void zfpm_rnodes_iter_init(zfpm_rnodes_iter_t *iter)
/*
* zfpm_rnodes_iter_next
*/
-static inline struct route_node *zfpm_rnodes_iter_next(zfpm_rnodes_iter_t *iter)
+static inline struct route_node *
+zfpm_rnodes_iter_next(struct zfpm_rnodes_iter *iter)
{
struct route_node *rn;
struct route_table *table;
@@ -389,7 +389,7 @@ static inline struct route_node *zfpm_rnodes_iter_next(zfpm_rnodes_iter_t *iter)
/*
* zfpm_rnodes_iter_pause
*/
-static inline void zfpm_rnodes_iter_pause(zfpm_rnodes_iter_t *iter)
+static inline void zfpm_rnodes_iter_pause(struct zfpm_rnodes_iter *iter)
{
route_table_iter_pause(&iter->iter);
}
@@ -397,7 +397,7 @@ static inline void zfpm_rnodes_iter_pause(zfpm_rnodes_iter_t *iter)
/*
* zfpm_rnodes_iter_cleanup
*/
-static inline void zfpm_rnodes_iter_cleanup(zfpm_rnodes_iter_t *iter)
+static inline void zfpm_rnodes_iter_cleanup(struct zfpm_rnodes_iter *iter)
{
route_table_iter_cleanup(&iter->iter);
rib_tables_iter_cleanup(&iter->tables_iter);
@@ -408,7 +408,7 @@ static inline void zfpm_rnodes_iter_cleanup(zfpm_rnodes_iter_t *iter)
*
* Initialize a statistics block.
*/
-static inline void zfpm_stats_init(zfpm_stats_t *stats)
+static inline void zfpm_stats_init(struct zfpm_stats *stats)
{
memset(stats, 0, sizeof(*stats));
}
@@ -416,7 +416,7 @@ static inline void zfpm_stats_init(zfpm_stats_t *stats)
/*
* zfpm_stats_reset
*/
-static inline void zfpm_stats_reset(zfpm_stats_t *stats)
+static inline void zfpm_stats_reset(struct zfpm_stats *stats)
{
zfpm_stats_init(stats);
}
@@ -424,7 +424,8 @@ static inline void zfpm_stats_reset(zfpm_stats_t *stats)
/*
* zfpm_stats_copy
*/
-static inline void zfpm_stats_copy(const zfpm_stats_t *src, zfpm_stats_t *dest)
+static inline void zfpm_stats_copy(const struct zfpm_stats *src,
+ struct zfpm_stats *dest)
{
memcpy(dest, src, sizeof(*dest));
}
@@ -440,8 +441,9 @@ static inline void zfpm_stats_copy(const zfpm_stats_t *src, zfpm_stats_t *dest)
* structure is composed entirely of counters. This can easily be
* changed when necessary.
*/
-static void zfpm_stats_compose(const zfpm_stats_t *s1, const zfpm_stats_t *s2,
- zfpm_stats_t *result)
+static void zfpm_stats_compose(const struct zfpm_stats *s1,
+ const struct zfpm_stats *s2,
+ struct zfpm_stats *result)
{
const unsigned long *p1, *p2;
unsigned long *result_p;
@@ -451,7 +453,7 @@ static void zfpm_stats_compose(const zfpm_stats_t *s1, const zfpm_stats_t *s2,
p2 = (const unsigned long *)s2;
result_p = (unsigned long *)result;
- num_counters = (sizeof(zfpm_stats_t) / sizeof(unsigned long));
+ num_counters = (sizeof(struct zfpm_stats) / sizeof(unsigned long));
for (i = 0; i < num_counters; i++) {
result_p[i] = p1[i] + p2[i];
@@ -512,7 +514,7 @@ static inline void zfpm_connect_off(void)
static int zfpm_conn_up_thread_cb(struct thread *thread)
{
struct route_node *rnode;
- zfpm_rnodes_iter_t *iter;
+ struct zfpm_rnodes_iter *iter;
rib_dest_t *dest;
zfpm_g->t_conn_up = NULL;
@@ -626,7 +628,7 @@ static void zfpm_connect_check(void)
static int zfpm_conn_down_thread_cb(struct thread *thread)
{
struct route_node *rnode;
- zfpm_rnodes_iter_t *iter;
+ struct zfpm_rnodes_iter *iter;
rib_dest_t *dest;
struct fpm_mac_info_t *mac = NULL;
@@ -1308,9 +1310,9 @@ static int zfpm_connect_cb(struct thread *t)
*
* Move state machine into the given state.
*/
-static void zfpm_set_state(zfpm_state_t state, const char *reason)
+static void zfpm_set_state(enum zfpm_state state, const char *reason)
{
- zfpm_state_t cur_state = zfpm_g->state;
+ enum zfpm_state cur_state = zfpm_g->state;
if (!reason)
reason = "Unknown";
@@ -1649,7 +1651,7 @@ static void zfpm_iterate_rmac_table(struct hash_bucket *backet, void *args)
}
/*
- * zfpm_stats_timer_cb
+ * struct zfpm_statsimer_cb
*/
static int zfpm_stats_timer_cb(struct thread *t)
{
@@ -1714,7 +1716,7 @@ void zfpm_start_stats_timer(void)
*/
static void zfpm_show_stats(struct vty *vty)
{
- zfpm_stats_t total_stats;
+ struct zfpm_stats total_stats;
time_t elapsed;
vty_out(vty, "\n%-40s %10s Last %2d secs\n\n", "Counter", "Total",
diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c
index 00909df1db..c580fe40d5 100644
--- a/zebra/zebra_fpm_netlink.c
+++ b/zebra/zebra_fpm_netlink.c
@@ -143,13 +143,13 @@ struct fpm_nh_encap_info_t {
};
/*
- * netlink_nh_info_t
+ * netlink_nh_info
*
* Holds information about a single nexthop for netlink. These info
* structures are transient and may contain pointers into rib
* data structures for convenience.
*/
-typedef struct netlink_nh_info_t_ {
+struct netlink_nh_info {
uint32_t if_index;
union g_addr *gateway;
@@ -160,14 +160,14 @@ typedef struct netlink_nh_info_t_ {
int recursive;
enum nexthop_types_t type;
struct fpm_nh_encap_info_t encap_info;
-} netlink_nh_info_t;
+};
/*
- * netlink_route_info_t
+ * netlink_route_info
*
* A structure for holding information for a netlink route message.
*/
-typedef struct netlink_route_info_t_ {
+struct netlink_route_info {
uint16_t nlmsg_type;
uint8_t rtm_type;
uint32_t rtm_table;
@@ -180,9 +180,9 @@ typedef struct netlink_route_info_t_ {
/*
* Nexthop structures
*/
- netlink_nh_info_t nhs[MULTIPATH_NUM];
+ struct netlink_nh_info nhs[MULTIPATH_NUM];
union g_addr *pref_src;
-} netlink_route_info_t;
+};
/*
* netlink_route_info_add_nh
@@ -192,11 +192,11 @@ typedef struct netlink_route_info_t_ {
*
* Returns true if a nexthop was added, false otherwise.
*/
-static int netlink_route_info_add_nh(netlink_route_info_t *ri,
+static int netlink_route_info_add_nh(struct netlink_route_info *ri,
struct nexthop *nexthop,
struct route_entry *re)
{
- netlink_nh_info_t nhi;
+ struct netlink_nh_info nhi;
union g_addr *src;
zebra_l3vni_t *zl3vni = NULL;
@@ -275,7 +275,7 @@ static uint8_t netlink_proto_from_route_type(int type)
*
* Returns true on success and false on failure.
*/
-static int netlink_route_info_fill(netlink_route_info_t *ri, int cmd,
+static int netlink_route_info_fill(struct netlink_route_info *ri, int cmd,
rib_dest_t *dest, struct route_entry *re)
{
struct nexthop *nexthop;
@@ -353,13 +353,13 @@ static int netlink_route_info_fill(netlink_route_info_t *ri, int cmd,
* Returns the number of bytes written to the buffer. 0 or a negative
* value indicates an error.
*/
-static int netlink_route_info_encode(netlink_route_info_t *ri, char *in_buf,
- size_t in_buf_len)
+static int netlink_route_info_encode(struct netlink_route_info *ri,
+ char *in_buf, size_t in_buf_len)
{
size_t bytelen;
unsigned int nexthop_num = 0;
size_t buf_offset;
- netlink_nh_info_t *nhi;
+ struct netlink_nh_info *nhi;
enum fpm_nh_encap_type_t encap;
struct rtattr *nest;
struct vxlan_encap_info_t *vxlan;
@@ -520,9 +520,10 @@ done:
*
* Helper function to log the information in a route_info structure.
*/
-static void zfpm_log_route_info(netlink_route_info_t *ri, const char *label)
+static void zfpm_log_route_info(struct netlink_route_info *ri,
+ const char *label)
{
- netlink_nh_info_t *nhi;
+ struct netlink_nh_info *nhi;
unsigned int i;
zfpm_debug("%s : %s %s/%d, Proto: %s, Metric: %u", label,
@@ -554,7 +555,7 @@ static void zfpm_log_route_info(netlink_route_info_t *ri, const char *label)
int zfpm_netlink_encode_route(int cmd, rib_dest_t *dest, struct route_entry *re,
char *in_buf, size_t in_buf_len)
{
- netlink_route_info_t ri_space, *ri;
+ struct netlink_route_info ri_space, *ri;
ri = &ri_space;
diff --git a/zebra/zebra_gr.c b/zebra/zebra_gr.c
index 19a280c0ca..a4f32dbf39 100644
--- a/zebra/zebra_gr.c
+++ b/zebra/zebra_gr.c
@@ -133,7 +133,7 @@ static void zebra_gr_client_info_delte(struct zserv *client,
zebra_route_string(client->proto));
/* Delete all the stale routes. */
- info->delete = true;
+ info->do_delete = true;
zebra_gr_delete_stale_routes(info);
XFREE(MTYPE_TMP, info);
@@ -456,7 +456,7 @@ static int32_t zebra_gr_route_stale_delete_timer_expiry(struct thread *thread)
/* Set the flag to indicate all stale route deletion */
if (thread->u.val == 1)
- info->delete = true;
+ info->do_delete = true;
cnt = zebra_gr_delete_stale_routes(info);
@@ -581,7 +581,7 @@ static int32_t zebra_gr_delete_stale_route(struct client_gr_info *info,
* Store the current prefix and afi
*/
if ((n >= ZEBRA_MAX_STALE_ROUTE_COUNT)
- && (info->delete == false)) {
+ && (info->do_delete == false)) {
info->current_afi = afi;
info->current_prefix = XCALLOC(
MTYPE_TMP,
diff --git a/zebra/zebra_l2.c b/zebra/zebra_l2.c
index e549d80a5c..4c0cc62fbf 100644
--- a/zebra/zebra_l2.c
+++ b/zebra/zebra_l2.c
@@ -53,7 +53,13 @@ static void map_slaves_to_bridge(struct interface *br_if, int link)
{
struct vrf *vrf;
struct interface *ifp;
+ struct zebra_vrf *zvrf;
+ struct zebra_ns *zns;
+ zvrf = zebra_vrf_lookup_by_id(br_if->vrf_id);
+ assert(zvrf);
+ zns = zvrf->zns;
+ assert(zns);
RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) {
FOR_ALL_INTERFACES (vrf, ifp) {
struct zebra_if *zif;
@@ -72,7 +78,8 @@ static void map_slaves_to_bridge(struct interface *br_if, int link)
br_slave = &zif->brslave_info;
if (link) {
- if (br_slave->bridge_ifindex == br_if->ifindex)
+ if (br_slave->bridge_ifindex == br_if->ifindex &&
+ br_slave->ns_id == zns->ns_id)
br_slave->br_if = br_if;
} else {
if (br_slave->br_if == br_if)
@@ -83,12 +90,14 @@ static void map_slaves_to_bridge(struct interface *br_if, int link)
}
/* Public functions */
-void zebra_l2_map_slave_to_bridge(struct zebra_l2info_brslave *br_slave)
+void zebra_l2_map_slave_to_bridge(struct zebra_l2info_brslave *br_slave,
+ struct zebra_ns *zns)
{
struct interface *br_if;
/* TODO: Handle change of master */
- br_if = if_lookup_by_index_per_ns(zebra_ns_lookup(NS_DEFAULT),
+ assert(zns);
+ br_if = if_lookup_by_index_per_ns(zebra_ns_lookup(zns->ns_id),
br_slave->bridge_ifindex);
if (br_if)
br_slave->br_if = br_if;
@@ -110,7 +119,7 @@ void zebra_l2_map_slave_to_bond(struct zebra_l2info_bondslave *bond_slave,
bond_slave->bond_if = bond_if;
else
bond_slave->bond_if = if_create_ifindex(bond_slave->bond_ifindex,
- vrf_id);
+ vrf_id, NULL);
}
void zebra_l2_unmap_slave_from_bond(struct zebra_l2info_bondslave *bond_slave)
@@ -237,23 +246,32 @@ void zebra_l2_vxlanif_del(struct interface *ifp)
* from a bridge before it can be mapped to another bridge.
*/
void zebra_l2if_update_bridge_slave(struct interface *ifp,
- ifindex_t bridge_ifindex)
+ ifindex_t bridge_ifindex,
+ ns_id_t ns_id)
{
struct zebra_if *zif;
ifindex_t old_bridge_ifindex;
+ ns_id_t old_ns_id;
+ struct zebra_vrf *zvrf;
zif = ifp->info;
assert(zif);
+ zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id);
+ if (!zvrf)
+ return;
+
old_bridge_ifindex = zif->brslave_info.bridge_ifindex;
- if (old_bridge_ifindex == bridge_ifindex)
+ old_ns_id = zif->brslave_info.ns_id;
+ if (old_bridge_ifindex == bridge_ifindex &&
+ old_ns_id == zif->brslave_info.ns_id)
return;
+ zif->brslave_info.ns_id = ns_id;
zif->brslave_info.bridge_ifindex = bridge_ifindex;
-
/* Set up or remove link with master */
if (bridge_ifindex != IFINDEX_INTERNAL) {
- zebra_l2_map_slave_to_bridge(&zif->brslave_info);
+ zebra_l2_map_slave_to_bridge(&zif->brslave_info, zvrf->zns);
/* In the case of VxLAN, invoke the handler for EVPN. */
if (zif->zif_type == ZEBRA_IF_VXLAN)
zebra_vxlan_if_update(ifp, ZEBRA_VXLIF_MASTER_CHANGE);
diff --git a/zebra/zebra_l2.h b/zebra/zebra_l2.h
index d9f0eec3f8..a3c780ee09 100644
--- a/zebra/zebra_l2.h
+++ b/zebra/zebra_l2.h
@@ -37,6 +37,7 @@ extern "C" {
struct zebra_l2info_brslave {
ifindex_t bridge_ifindex; /* Bridge Master */
struct interface *br_if; /* Pointer to master */
+ ns_id_t ns_id; /* network namespace where bridge is */
};
/* zebra L2 interface information - bridge interface */
@@ -55,6 +56,10 @@ struct zebra_l2info_vxlan {
struct in_addr vtep_ip; /* Local tunnel IP */
vlanid_t access_vlan; /* Access VLAN - for VLAN-aware bridge. */
struct in_addr mcast_grp;
+ ifindex_t ifindex_link; /* Interface index of interface
+ * linked with VXLAN
+ */
+ ns_id_t link_nsid;
};
struct zebra_l2info_bondslave {
@@ -77,7 +82,8 @@ union zebra_l2if_info {
#define IS_ZEBRA_IF_BRIDGE_VLAN_AWARE(zif) ((zif)->l2info.br.vlan_aware == 1)
-extern void zebra_l2_map_slave_to_bridge(struct zebra_l2info_brslave *br_slave);
+extern void zebra_l2_map_slave_to_bridge(struct zebra_l2info_brslave *br_slave,
+ struct zebra_ns *zns);
extern void
zebra_l2_unmap_slave_from_bridge(struct zebra_l2info_brslave *br_slave);
extern void
@@ -97,7 +103,8 @@ extern void zebra_l2_vxlanif_update_access_vlan(struct interface *ifp,
vlanid_t access_vlan);
extern void zebra_l2_vxlanif_del(struct interface *ifp);
extern void zebra_l2if_update_bridge_slave(struct interface *ifp,
- ifindex_t bridge_ifindex);
+ ifindex_t bridge_ifindex,
+ ns_id_t ns_id);
extern void zebra_l2if_update_bond_slave(struct interface *ifp,
ifindex_t bond_ifindex);
diff --git a/zebra/zebra_mpls.h b/zebra/zebra_mpls.h
index 33cb614346..e468fb9c1b 100644
--- a/zebra/zebra_mpls.h
+++ b/zebra/zebra_mpls.h
@@ -430,6 +430,7 @@ static inline uint8_t lsp_distance(enum lsp_types_t type)
case ZEBRA_LSP_NONE:
case ZEBRA_LSP_SHARP:
case ZEBRA_LSP_OSPF_SR:
+ case ZEBRA_LSP_ISIS_SR:
return 150;
}
@@ -457,6 +458,8 @@ static inline enum lsp_types_t lsp_type_from_re_type(int re_type)
return ZEBRA_LSP_BGP;
case ZEBRA_ROUTE_OSPF:
return ZEBRA_LSP_OSPF_SR;
+ case ZEBRA_ROUTE_ISIS:
+ return ZEBRA_LSP_ISIS_SR;
case ZEBRA_ROUTE_SHARP:
return ZEBRA_LSP_SHARP;
default:
@@ -478,6 +481,8 @@ static inline int re_type_from_lsp_type(enum lsp_types_t lsp_type)
return ZEBRA_ROUTE_BGP;
case ZEBRA_LSP_OSPF_SR:
return ZEBRA_ROUTE_OSPF;
+ case ZEBRA_LSP_ISIS_SR:
+ return ZEBRA_ROUTE_ISIS;
case ZEBRA_LSP_NONE:
return ZEBRA_ROUTE_KERNEL;
case ZEBRA_LSP_SHARP:
@@ -505,6 +510,8 @@ static inline const char *nhlfe_type2str(enum lsp_types_t lsp_type)
return "BGP";
case ZEBRA_LSP_OSPF_SR:
return "SR (OSPF)";
+ case ZEBRA_LSP_ISIS_SR:
+ return "SR (IS-IS)";
case ZEBRA_LSP_SHARP:
return "SHARP";
case ZEBRA_LSP_NONE:
diff --git a/zebra/zebra_nb.c b/zebra/zebra_nb.c
index 1f3468d6dc..25b8b44ec9 100644
--- a/zebra/zebra_nb.c
+++ b/zebra/zebra_nb.c
@@ -22,6 +22,40 @@
#include "libfrr.h"
#include "zebra_nb.h"
+const char *zebra_afi_safi_value2identity(afi_t afi, safi_t safi)
+{
+ if (afi == AFI_IP && safi == SAFI_UNICAST)
+ return "ipv4-unicast";
+ if (afi == AFI_IP6 && safi == SAFI_UNICAST)
+ return "ipv6-unicast";
+ if (afi == AFI_IP && safi == SAFI_MULTICAST)
+ return "ipv4-multicast";
+ if (afi == AFI_IP6 && safi == SAFI_MULTICAST)
+ return "ipv6-multicast";
+
+ return " ";
+}
+
+void zebra_afi_safi_identity2value(const char *key, afi_t *afi, safi_t *safi)
+{
+ if (strmatch(key, "frr-zebra:ipv4-unicast")) {
+ *afi = AFI_IP;
+ *safi = SAFI_UNICAST;
+ } else if (strmatch(key, "frr-zebra:ipv6-unicast")) {
+ *afi = AFI_IP6;
+ *safi = SAFI_UNICAST;
+ } else if (strmatch(key, "frr-zebra:ipv4-multicast")) {
+ *afi = AFI_IP;
+ *safi = SAFI_MULTICAST;
+ } else if (strmatch(key, "frr-zebra:ipv6-multicast")) {
+ *afi = AFI_IP6;
+ *safi = SAFI_MULTICAST;
+ } else {
+ *afi = AFI_UNSPEC;
+ *safi = SAFI_UNSPEC;
+ }
+}
+
/* clang-format off */
const struct frr_yang_module_info frr_zebra_info = {
.name = "frr-zebra",
@@ -420,221 +454,221 @@ const struct frr_yang_module_info frr_zebra_info = {
}
},
{
- .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib",
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib",
.cbs = {
- .create = lib_vrf_ribs_rib_create,
- .destroy = lib_vrf_ribs_rib_destroy,
- .get_next = lib_vrf_ribs_rib_get_next,
- .get_keys = lib_vrf_ribs_rib_get_keys,
- .lookup_entry = lib_vrf_ribs_rib_lookup_entry,
+ .create = lib_vrf_zebra_ribs_rib_create,
+ .destroy = lib_vrf_zebra_ribs_rib_destroy,
+ .get_next = lib_vrf_zebra_ribs_rib_get_next,
+ .get_keys = lib_vrf_zebra_ribs_rib_get_keys,
+ .lookup_entry = lib_vrf_zebra_ribs_rib_lookup_entry,
}
},
{
- .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route",
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route",
.cbs = {
- .get_next = lib_vrf_ribs_rib_route_get_next,
- .get_keys = lib_vrf_ribs_rib_route_get_keys,
- .lookup_entry = lib_vrf_ribs_rib_route_lookup_entry,
+ .get_next = lib_vrf_zebra_ribs_rib_route_get_next,
+ .get_keys = lib_vrf_zebra_ribs_rib_route_get_keys,
+ .lookup_entry = lib_vrf_zebra_ribs_rib_route_lookup_entry,
}
},
{
- .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/prefix",
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/prefix",
.cbs = {
- .get_elem = lib_vrf_ribs_rib_route_prefix_get_elem,
+ .get_elem = lib_vrf_zebra_ribs_rib_route_prefix_get_elem,
}
},
{
- .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry",
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry",
.cbs = {
- .get_next = lib_vrf_ribs_rib_route_route_entry_get_next,
- .get_keys = lib_vrf_ribs_rib_route_route_entry_get_keys,
- .lookup_entry = lib_vrf_ribs_rib_route_route_entry_lookup_entry,
+ .get_next = lib_vrf_zebra_ribs_rib_route_route_entry_get_next,
+ .get_keys = lib_vrf_zebra_ribs_rib_route_route_entry_get_keys,
+ .lookup_entry = lib_vrf_zebra_ribs_rib_route_route_entry_lookup_entry,
}
},
{
- .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/protocol",
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/protocol",
.cbs = {
- .get_elem = lib_vrf_ribs_rib_route_route_entry_protocol_get_elem,
+ .get_elem = lib_vrf_zebra_ribs_rib_route_route_entry_protocol_get_elem,
}
},
{
- .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/instance",
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/instance",
.cbs = {
- .get_elem = lib_vrf_ribs_rib_route_route_entry_instance_get_elem,
+ .get_elem = lib_vrf_zebra_ribs_rib_route_route_entry_instance_get_elem,
}
},
{
- .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/distance",
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/distance",
.cbs = {
- .get_elem = lib_vrf_ribs_rib_route_route_entry_distance_get_elem,
+ .get_elem = lib_vrf_zebra_ribs_rib_route_route_entry_distance_get_elem,
}
},
{
- .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/metric",
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/metric",
.cbs = {
- .get_elem = lib_vrf_ribs_rib_route_route_entry_metric_get_elem,
+ .get_elem = lib_vrf_zebra_ribs_rib_route_route_entry_metric_get_elem,
}
},
{
- .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/tag",
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/tag",
.cbs = {
- .get_elem = lib_vrf_ribs_rib_route_route_entry_tag_get_elem,
+ .get_elem = lib_vrf_zebra_ribs_rib_route_route_entry_tag_get_elem,
}
},
{
- .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/selected",
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/selected",
.cbs = {
- .get_elem = lib_vrf_ribs_rib_route_route_entry_selected_get_elem,
+ .get_elem = lib_vrf_zebra_ribs_rib_route_route_entry_selected_get_elem,
}
},
{
- .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/installed",
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/installed",
.cbs = {
- .get_elem = lib_vrf_ribs_rib_route_route_entry_installed_get_elem,
+ .get_elem = lib_vrf_zebra_ribs_rib_route_route_entry_installed_get_elem,
}
},
{
- .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/failed",
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/failed",
.cbs = {
- .get_elem = lib_vrf_ribs_rib_route_route_entry_failed_get_elem,
+ .get_elem = lib_vrf_zebra_ribs_rib_route_route_entry_failed_get_elem,
}
},
{
- .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/queued",
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/queued",
.cbs = {
- .get_elem = lib_vrf_ribs_rib_route_route_entry_queued_get_elem,
+ .get_elem = lib_vrf_zebra_ribs_rib_route_route_entry_queued_get_elem,
}
},
{
- .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/internal-flags",
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/internal-flags",
.cbs = {
- .get_elem = lib_vrf_ribs_rib_route_route_entry_internal_flags_get_elem,
+ .get_elem = lib_vrf_zebra_ribs_rib_route_route_entry_internal_flags_get_elem,
}
},
{
- .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/internal-status",
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/internal-status",
.cbs = {
- .get_elem = lib_vrf_ribs_rib_route_route_entry_internal_status_get_elem,
+ .get_elem = lib_vrf_zebra_ribs_rib_route_route_entry_internal_status_get_elem,
}
},
{
- .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/uptime",
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/uptime",
.cbs = {
- .get_elem = lib_vrf_ribs_rib_route_route_entry_uptime_get_elem,
+ .get_elem = lib_vrf_zebra_ribs_rib_route_route_entry_uptime_get_elem,
}
},
{
- .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group",
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group",
.cbs = {
- .get_next = lib_vrf_ribs_rib_route_route_entry_nexthop_group_get_next,
- .get_keys = lib_vrf_ribs_rib_route_route_entry_nexthop_group_get_keys,
- .lookup_entry = lib_vrf_ribs_rib_route_route_entry_nexthop_group_lookup_entry,
+ .get_next = lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_get_next,
+ .get_keys = lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_get_keys,
+ .lookup_entry = lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_lookup_entry,
}
},
{
- .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/name",
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/name",
.cbs = {
- .get_elem = lib_vrf_ribs_rib_route_route_entry_nexthop_group_name_get_elem,
+ .get_elem = lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_name_get_elem,
}
},
{
- .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop",
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop",
.cbs = {
- .get_next = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_get_next,
- .get_keys = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_get_keys,
- .lookup_entry = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_lookup_entry,
+ .get_next = lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_get_next,
+ .get_keys = lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_get_keys,
+ .lookup_entry = lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_lookup_entry,
}
},
{
- .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/nh-type",
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/nh-type",
.cbs = {
- .get_elem = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_nh_type_get_elem,
+ .get_elem = lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_nh_type_get_elem,
}
},
{
- .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/vrf",
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/vrf",
.cbs = {
- .get_elem = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_vrf_get_elem,
+ .get_elem = lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_vrf_get_elem,
}
},
{
- .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/gateway",
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/gateway",
.cbs = {
- .get_elem = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_gateway_get_elem,
+ .get_elem = lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_gateway_get_elem,
}
},
{
- .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/interface",
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/interface",
.cbs = {
- .get_elem = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_interface_get_elem,
+ .get_elem = lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_interface_get_elem,
}
},
{
- .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/bh-type",
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/bh-type",
.cbs = {
- .get_elem = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_bh_type_get_elem,
+ .get_elem = lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_bh_type_get_elem,
}
},
{
- .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/onlink",
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/onlink",
.cbs = {
- .get_elem = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_onlink_get_elem,
+ .get_elem = lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_onlink_get_elem,
}
},
{
- .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/mpls-label-stack/entry",
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/mpls-label-stack/entry",
.cbs = {
- .get_next = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_get_next,
- .get_keys = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_get_keys,
- .lookup_entry = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_lookup_entry,
+ .get_next = lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_get_next,
+ .get_keys = lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_get_keys,
+ .lookup_entry = lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_lookup_entry,
}
},
{
- .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/mpls-label-stack/entry/id",
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/mpls-label-stack/entry/id",
.cbs = {
- .get_elem = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_id_get_elem,
+ .get_elem = lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_id_get_elem,
}
},
{
- .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/mpls-label-stack/entry/label",
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/mpls-label-stack/entry/label",
.cbs = {
- .get_elem = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_label_get_elem,
+ .get_elem = lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_label_get_elem,
}
},
{
- .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/mpls-label-stack/entry/ttl",
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/mpls-label-stack/entry/ttl",
.cbs = {
- .get_elem = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_ttl_get_elem,
+ .get_elem = lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_ttl_get_elem,
}
},
{
- .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/mpls-label-stack/entry/traffic-class",
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/mpls-label-stack/entry/traffic-class",
.cbs = {
- .get_elem = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_traffic_class_get_elem,
+ .get_elem = lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_traffic_class_get_elem,
}
},
{
- .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/duplicate",
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/duplicate",
.cbs = {
- .get_elem = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_duplicate_get_elem,
+ .get_elem = lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_duplicate_get_elem,
}
},
{
- .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/recursive",
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/recursive",
.cbs = {
- .get_elem = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_recursive_get_elem,
+ .get_elem = lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_recursive_get_elem,
}
},
{
- .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/active",
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/active",
.cbs = {
- .get_elem = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_active_get_elem,
+ .get_elem = lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_active_get_elem,
}
},
{
- .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/fib",
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/fib",
.cbs = {
- .get_elem = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_fib_get_elem,
+ .get_elem = lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_fib_get_elem,
}
},
{
@@ -680,9 +714,9 @@ const struct frr_yang_module_info frr_zebra_info = {
}
},
{
- .xpath = "/frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/weight",
+ .xpath = "/frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/weight",
.cbs = {
- .get_elem = lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_weight_get_elem,
+ .get_elem = lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_weight_get_elem,
}
},
{
diff --git a/zebra/zebra_nb.h b/zebra/zebra_nb.h
index 09a9edff99..15350eb53b 100644
--- a/zebra/zebra_nb.h
+++ b/zebra/zebra_nb.h
@@ -26,6 +26,10 @@ extern "C" {
extern const struct frr_yang_module_info frr_zebra_info;
+/* helper functions */
+const char *zebra_afi_safi_value2identity(afi_t afi, safi_t safi);
+void zebra_afi_safi_identity2value(const char *key, afi_t *afi, safi_t *safi);
+
/* prototypes */
int get_route_information_rpc(struct nb_cb_rpc_args *args);
int get_v6_mroute_info_rpc(struct nb_cb_rpc_args *args);
@@ -155,165 +159,172 @@ struct yang_data *lib_interface_zebra_state_remote_vtep_get_elem(
struct nb_cb_get_elem_args *args);
struct yang_data *lib_interface_zebra_state_mcast_group_get_elem(
struct nb_cb_get_elem_args *args);
-int lib_vrf_ribs_rib_create(struct nb_cb_create_args *args);
-int lib_vrf_ribs_rib_destroy(struct nb_cb_destroy_args *args);
-const void *lib_vrf_ribs_rib_get_next(struct nb_cb_get_next_args *args);
-int lib_vrf_ribs_rib_get_keys(struct nb_cb_get_keys_args *args);
-const void *lib_vrf_ribs_rib_lookup_entry(struct nb_cb_lookup_entry_args *args);
-const void *lib_vrf_ribs_rib_route_get_next(struct nb_cb_get_next_args *args);
-int lib_vrf_ribs_rib_route_get_keys(struct nb_cb_get_keys_args *args);
+int lib_vrf_zebra_ribs_rib_create(struct nb_cb_create_args *args);
+int lib_vrf_zebra_ribs_rib_destroy(struct nb_cb_destroy_args *args);
+const void *lib_vrf_zebra_ribs_rib_get_next(struct nb_cb_get_next_args *args);
+int lib_vrf_zebra_ribs_rib_get_keys(struct nb_cb_get_keys_args *args);
const void *
-lib_vrf_ribs_rib_route_lookup_entry(struct nb_cb_lookup_entry_args *args);
-struct yang_data *
-lib_vrf_ribs_rib_route_prefix_get_elem(struct nb_cb_get_elem_args *args);
-struct yang_data *
-lib_vrf_ribs_rib_route_protocol_get_elem(struct nb_cb_get_elem_args *args);
-struct yang_data *
-lib_vrf_ribs_rib_route_protocol_v6_get_elem(struct nb_cb_get_elem_args *args);
-struct yang_data *
-lib_vrf_ribs_rib_route_vrf_get_elem(struct nb_cb_get_elem_args *args);
-struct yang_data *
-lib_vrf_ribs_rib_route_distance_get_elem(struct nb_cb_get_elem_args *args);
+lib_vrf_zebra_ribs_rib_lookup_entry(struct nb_cb_lookup_entry_args *args);
+const void *
+lib_vrf_zebra_ribs_rib_route_get_next(struct nb_cb_get_next_args *args);
+int lib_vrf_zebra_ribs_rib_route_get_keys(struct nb_cb_get_keys_args *args);
+const void *
+lib_vrf_zebra_ribs_rib_route_lookup_entry(struct nb_cb_lookup_entry_args *args);
struct yang_data *
-lib_vrf_ribs_rib_route_metric_get_elem(struct nb_cb_get_elem_args *args);
+lib_vrf_zebra_ribs_rib_route_prefix_get_elem(struct nb_cb_get_elem_args *args);
+struct yang_data *lib_vrf_zebra_ribs_rib_route_protocol_get_elem(
+ struct nb_cb_get_elem_args *args);
+struct yang_data *lib_vrf_zebra_ribs_rib_route_protocol_v6_get_elem(
+ struct nb_cb_get_elem_args *args);
struct yang_data *
-lib_vrf_ribs_rib_route_tag_get_elem(struct nb_cb_get_elem_args *args);
+lib_vrf_zebra_ribs_rib_route_vrf_get_elem(struct nb_cb_get_elem_args *args);
+struct yang_data *lib_vrf_zebra_ribs_rib_route_distance_get_elem(
+ struct nb_cb_get_elem_args *args);
struct yang_data *
-lib_vrf_ribs_rib_route_selected_get_elem(struct nb_cb_get_elem_args *args);
+lib_vrf_zebra_ribs_rib_route_metric_get_elem(struct nb_cb_get_elem_args *args);
struct yang_data *
-lib_vrf_ribs_rib_route_installed_get_elem(struct nb_cb_get_elem_args *args);
+lib_vrf_zebra_ribs_rib_route_tag_get_elem(struct nb_cb_get_elem_args *args);
+struct yang_data *lib_vrf_zebra_ribs_rib_route_selected_get_elem(
+ struct nb_cb_get_elem_args *args);
+struct yang_data *lib_vrf_zebra_ribs_rib_route_installed_get_elem(
+ struct nb_cb_get_elem_args *args);
struct yang_data *
-lib_vrf_ribs_rib_route_failed_get_elem(struct nb_cb_get_elem_args *args);
+lib_vrf_zebra_ribs_rib_route_failed_get_elem(struct nb_cb_get_elem_args *args);
struct yang_data *
-lib_vrf_ribs_rib_route_queued_get_elem(struct nb_cb_get_elem_args *args);
-struct yang_data *lib_vrf_ribs_rib_route_internal_flags_get_elem(
+lib_vrf_zebra_ribs_rib_route_queued_get_elem(struct nb_cb_get_elem_args *args);
+struct yang_data *lib_vrf_zebra_ribs_rib_route_internal_flags_get_elem(
struct nb_cb_get_elem_args *args);
-struct yang_data *lib_vrf_ribs_rib_route_internal_status_get_elem(
+struct yang_data *lib_vrf_zebra_ribs_rib_route_internal_status_get_elem(
struct nb_cb_get_elem_args *args);
struct yang_data *
-lib_vrf_ribs_rib_route_uptime_get_elem(struct nb_cb_get_elem_args *args);
-const void *
-lib_vrf_ribs_rib_route_nexthop_group_get_next(struct nb_cb_get_next_args *args);
-int lib_vrf_ribs_rib_route_nexthop_group_get_keys(
+lib_vrf_zebra_ribs_rib_route_uptime_get_elem(struct nb_cb_get_elem_args *args);
+const void *lib_vrf_zebra_ribs_rib_route_nexthop_group_get_next(
+ struct nb_cb_get_next_args *args);
+int lib_vrf_zebra_ribs_rib_route_nexthop_group_get_keys(
struct nb_cb_get_keys_args *args);
-const void *lib_vrf_ribs_rib_route_nexthop_group_lookup_entry(
+const void *lib_vrf_zebra_ribs_rib_route_nexthop_group_lookup_entry(
struct nb_cb_lookup_entry_args *args);
-struct yang_data *lib_vrf_ribs_rib_route_nexthop_group_name_get_elem(
+struct yang_data *lib_vrf_zebra_ribs_rib_route_nexthop_group_name_get_elem(
struct nb_cb_get_elem_args *args);
-const void *lib_vrf_ribs_rib_route_nexthop_group_frr_nexthops_nexthop_get_next(
+const void *
+lib_vrf_zebra_ribs_rib_route_nexthop_group_frr_nexthops_nexthop_get_next(
struct nb_cb_get_next_args *args);
-int lib_vrf_ribs_rib_route_nexthop_group_frr_nexthops_nexthop_get_keys(
+int lib_vrf_zebra_ribs_rib_route_nexthop_group_frr_nexthops_nexthop_get_keys(
struct nb_cb_get_keys_args *args);
-int lib_vrf_ribs_rib_create(struct nb_cb_create_args *args);
-int lib_vrf_ribs_rib_destroy(struct nb_cb_destroy_args *args);
-const void *lib_vrf_ribs_rib_get_next(struct nb_cb_get_next_args *args);
-int lib_vrf_ribs_rib_get_keys(struct nb_cb_get_keys_args *args);
-const void *lib_vrf_ribs_rib_lookup_entry(struct nb_cb_lookup_entry_args *args);
-const void *lib_vrf_ribs_rib_route_get_next(struct nb_cb_get_next_args *args);
-int lib_vrf_ribs_rib_route_get_keys(struct nb_cb_get_keys_args *args);
+int lib_vrf_zebra_ribs_rib_create(struct nb_cb_create_args *args);
+int lib_vrf_zebra_ribs_rib_destroy(struct nb_cb_destroy_args *args);
+const void *lib_vrf_zebra_ribs_rib_get_next(struct nb_cb_get_next_args *args);
+int lib_vrf_zebra_ribs_rib_get_keys(struct nb_cb_get_keys_args *args);
const void *
-lib_vrf_ribs_rib_route_lookup_entry(struct nb_cb_lookup_entry_args *args);
-struct yang_data *
-lib_vrf_ribs_rib_route_prefix_get_elem(struct nb_cb_get_elem_args *args);
+lib_vrf_zebra_ribs_rib_lookup_entry(struct nb_cb_lookup_entry_args *args);
const void *
-lib_vrf_ribs_rib_route_route_entry_get_next(struct nb_cb_get_next_args *args);
-int lib_vrf_ribs_rib_route_route_entry_get_keys(
+lib_vrf_zebra_ribs_rib_route_get_next(struct nb_cb_get_next_args *args);
+int lib_vrf_zebra_ribs_rib_route_get_keys(struct nb_cb_get_keys_args *args);
+const void *
+lib_vrf_zebra_ribs_rib_route_lookup_entry(struct nb_cb_lookup_entry_args *args);
+struct yang_data *
+lib_vrf_zebra_ribs_rib_route_prefix_get_elem(struct nb_cb_get_elem_args *args);
+const void *lib_vrf_zebra_ribs_rib_route_route_entry_get_next(
+ struct nb_cb_get_next_args *args);
+int lib_vrf_zebra_ribs_rib_route_route_entry_get_keys(
struct nb_cb_get_keys_args *args);
-const void *lib_vrf_ribs_rib_route_route_entry_lookup_entry(
+const void *lib_vrf_zebra_ribs_rib_route_route_entry_lookup_entry(
struct nb_cb_lookup_entry_args *args);
-struct yang_data *lib_vrf_ribs_rib_route_route_entry_protocol_get_elem(
+struct yang_data *lib_vrf_zebra_ribs_rib_route_route_entry_protocol_get_elem(
struct nb_cb_get_elem_args *args);
-struct yang_data *lib_vrf_ribs_rib_route_route_entry_instance_get_elem(
+struct yang_data *lib_vrf_zebra_ribs_rib_route_route_entry_instance_get_elem(
struct nb_cb_get_elem_args *args);
-struct yang_data *lib_vrf_ribs_rib_route_route_entry_distance_get_elem(
+struct yang_data *lib_vrf_zebra_ribs_rib_route_route_entry_distance_get_elem(
struct nb_cb_get_elem_args *args);
-struct yang_data *lib_vrf_ribs_rib_route_route_entry_metric_get_elem(
+struct yang_data *lib_vrf_zebra_ribs_rib_route_route_entry_metric_get_elem(
struct nb_cb_get_elem_args *args);
-struct yang_data *lib_vrf_ribs_rib_route_route_entry_tag_get_elem(
+struct yang_data *lib_vrf_zebra_ribs_rib_route_route_entry_tag_get_elem(
struct nb_cb_get_elem_args *args);
-struct yang_data *lib_vrf_ribs_rib_route_route_entry_selected_get_elem(
+struct yang_data *lib_vrf_zebra_ribs_rib_route_route_entry_selected_get_elem(
struct nb_cb_get_elem_args *args);
-struct yang_data *lib_vrf_ribs_rib_route_route_entry_installed_get_elem(
+struct yang_data *lib_vrf_zebra_ribs_rib_route_route_entry_installed_get_elem(
struct nb_cb_get_elem_args *args);
-struct yang_data *lib_vrf_ribs_rib_route_route_entry_failed_get_elem(
+struct yang_data *lib_vrf_zebra_ribs_rib_route_route_entry_failed_get_elem(
struct nb_cb_get_elem_args *args);
-struct yang_data *lib_vrf_ribs_rib_route_route_entry_queued_get_elem(
+struct yang_data *lib_vrf_zebra_ribs_rib_route_route_entry_queued_get_elem(
struct nb_cb_get_elem_args *args);
-struct yang_data *lib_vrf_ribs_rib_route_route_entry_internal_flags_get_elem(
+struct yang_data *
+lib_vrf_zebra_ribs_rib_route_route_entry_internal_flags_get_elem(
struct nb_cb_get_elem_args *args);
-struct yang_data *lib_vrf_ribs_rib_route_route_entry_internal_status_get_elem(
+struct yang_data *
+lib_vrf_zebra_ribs_rib_route_route_entry_internal_status_get_elem(
struct nb_cb_get_elem_args *args);
-struct yang_data *lib_vrf_ribs_rib_route_route_entry_uptime_get_elem(
+struct yang_data *lib_vrf_zebra_ribs_rib_route_route_entry_uptime_get_elem(
struct nb_cb_get_elem_args *args);
-const void *lib_vrf_ribs_rib_route_route_entry_nexthop_group_get_next(
+const void *lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_get_next(
struct nb_cb_get_next_args *args);
-int lib_vrf_ribs_rib_route_route_entry_nexthop_group_get_keys(
+int lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_get_keys(
struct nb_cb_get_keys_args *args);
-const void *lib_vrf_ribs_rib_route_route_entry_nexthop_group_lookup_entry(
+const void *lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_lookup_entry(
struct nb_cb_lookup_entry_args *args);
struct yang_data *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_name_get_elem(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_name_get_elem(
struct nb_cb_get_elem_args *args);
const void *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_get_next(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_get_next(
struct nb_cb_get_next_args *args);
-int lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_get_keys(
+int lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_get_keys(
struct nb_cb_get_keys_args *args);
const void *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_lookup_entry(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_lookup_entry(
struct nb_cb_lookup_entry_args *args);
struct yang_data *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_nh_type_get_elem(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_nh_type_get_elem(
struct nb_cb_get_elem_args *args);
struct yang_data *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_vrf_get_elem(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_vrf_get_elem(
struct nb_cb_get_elem_args *args);
struct yang_data *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_gateway_get_elem(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_gateway_get_elem(
struct nb_cb_get_elem_args *args);
struct yang_data *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_interface_get_elem(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_interface_get_elem(
struct nb_cb_get_elem_args *args);
struct yang_data *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_bh_type_get_elem(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_bh_type_get_elem(
struct nb_cb_get_elem_args *args);
struct yang_data *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_onlink_get_elem(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_onlink_get_elem(
struct nb_cb_get_elem_args *args);
const void *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_get_next(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_get_next(
struct nb_cb_get_next_args *args);
-int lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_get_keys(
+int lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_get_keys(
struct nb_cb_get_keys_args *args);
const void *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_lookup_entry(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_lookup_entry(
struct nb_cb_lookup_entry_args *args);
struct yang_data *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_id_get_elem(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_id_get_elem(
struct nb_cb_get_elem_args *args);
struct yang_data *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_label_get_elem(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_label_get_elem(
struct nb_cb_get_elem_args *args);
struct yang_data *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_ttl_get_elem(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_ttl_get_elem(
struct nb_cb_get_elem_args *args);
struct yang_data *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_traffic_class_get_elem(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_traffic_class_get_elem(
struct nb_cb_get_elem_args *args);
struct yang_data *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_duplicate_get_elem(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_duplicate_get_elem(
struct nb_cb_get_elem_args *args);
struct yang_data *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_recursive_get_elem(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_recursive_get_elem(
struct nb_cb_get_elem_args *args);
struct yang_data *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_active_get_elem(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_active_get_elem(
struct nb_cb_get_elem_args *args);
struct yang_data *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_fib_get_elem(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_fib_get_elem(
struct nb_cb_get_elem_args *args);
struct yang_data *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_weight_get_elem(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_weight_get_elem(
struct nb_cb_get_elem_args *args);
#ifdef __cplusplus
diff --git a/zebra/zebra_nb_config.c b/zebra/zebra_nb_config.c
index dbe265da8c..5b87a18a06 100644
--- a/zebra/zebra_nb_config.c
+++ b/zebra/zebra_nb_config.c
@@ -29,6 +29,8 @@
#include "zebra_nb.h"
#include "zebra/interface.h"
#include "zebra/connected.h"
+#include "zebra/zebra_router.h"
+#include "zebra/debug.h"
/*
* XPath: /frr-zebra:zebra/mcast-rpf-lookup
@@ -1216,32 +1218,56 @@ int lib_interface_zebra_bandwidth_destroy(struct nb_cb_destroy_args *args)
}
/*
- * XPath: /frr-vrf:lib/vrf/frr-zebra:ribs/rib
+ * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib
*/
-int lib_vrf_ribs_rib_create(struct nb_cb_create_args *args)
+int lib_vrf_zebra_ribs_rib_create(struct nb_cb_create_args *args)
{
+ struct vrf *vrf;
+ afi_t afi;
+ safi_t safi;
+ struct zebra_vrf *zvrf;
+ struct zebra_router_table *zrt;
+ uint32_t table_id;
+ const char *afi_safi_name;
+
+ vrf = nb_running_get_entry(args->dnode, NULL, false);
+ zvrf = vrf_info_lookup(vrf->vrf_id);
+ table_id = yang_dnode_get_uint32(args->dnode, "./table-id");
+ if (!table_id)
+ table_id = zvrf->table_id;
+
+ afi_safi_name = yang_dnode_get_string(args->dnode, "./afi-safi-name");
+ zebra_afi_safi_identity2value(afi_safi_name, &afi, &safi);
+
+ zrt = zebra_router_find_zrt(zvrf, table_id, afi, safi);
+
switch (args->event) {
case NB_EV_VALIDATE:
+ if (!zrt) {
+ zlog_debug("%s: vrf %s table is not found.", __func__,
+ vrf->name);
+ return NB_ERR_VALIDATION;
+ }
+ break;
case NB_EV_PREPARE:
case NB_EV_ABORT:
+ break;
case NB_EV_APPLY:
- /* TODO: implement me. */
+
+ nb_running_set_entry(args->dnode, zrt);
+
break;
}
return NB_OK;
}
-int lib_vrf_ribs_rib_destroy(struct nb_cb_destroy_args *args)
+int lib_vrf_zebra_ribs_rib_destroy(struct nb_cb_destroy_args *args)
{
- switch (args->event) {
- case NB_EV_VALIDATE:
- case NB_EV_PREPARE:
- case NB_EV_ABORT:
- case NB_EV_APPLY:
- /* TODO: implement me. */
- break;
- }
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ nb_running_unset_entry(args->dnode);
return NB_OK;
}
diff --git a/zebra/zebra_nb_state.c b/zebra/zebra_nb_state.c
index 09c76e6022..afbabe342c 100644
--- a/zebra/zebra_nb_state.c
+++ b/zebra/zebra_nb_state.c
@@ -22,6 +22,9 @@
#include "libfrr.h"
#include "zebra_nb.h"
#include "zebra/interface.h"
+#include "zebra/zebra_router.h"
+#include "zebra/debug.h"
+#include "printfrr.h"
/*
* XPath: /frr-interface:lib/interface/frr-zebra:zebra/state/up-count
@@ -147,348 +150,713 @@ lib_interface_zebra_state_mcast_group_get_elem(struct nb_cb_get_elem_args *args)
return yang_data_new_ipv4(args->xpath, &vxlan_info->mcast_grp);
}
-const void *lib_vrf_ribs_rib_get_next(struct nb_cb_get_next_args *args)
+const void *lib_vrf_zebra_ribs_rib_get_next(struct nb_cb_get_next_args *args)
{
- /* TODO: implement me. */
- return NULL;
+ struct vrf *vrf = (struct vrf *)args->parent_list_entry;
+ struct zebra_router_table *zrt =
+ (struct zebra_router_table *)args->list_entry;
+
+ struct zebra_vrf *zvrf;
+ afi_t afi;
+ safi_t safi;
+
+ zvrf = zebra_vrf_lookup_by_id(vrf->vrf_id);
+
+ if (args->list_entry == NULL) {
+ afi = AFI_IP;
+ safi = SAFI_UNICAST;
+
+ zrt = zebra_router_find_zrt(zvrf, zvrf->table_id, afi, safi);
+ if (zrt == NULL)
+ return NULL;
+ } else {
+ zrt = RB_NEXT(zebra_router_table_head, zrt);
+ /* vrf_id/ns_id do not match, only walk for the given VRF */
+ while (zrt && zrt->ns_id != zvrf->zns->ns_id)
+ zrt = RB_NEXT(zebra_router_table_head, zrt);
+ }
+
+ return zrt;
}
-int lib_vrf_ribs_rib_get_keys(struct nb_cb_get_keys_args *args)
+int lib_vrf_zebra_ribs_rib_get_keys(struct nb_cb_get_keys_args *args)
{
- /* TODO: implement me. */
+ const struct zebra_router_table *zrt = args->list_entry;
+
+ args->keys->num = 2;
+
+ snprintfrr(args->keys->key[0], sizeof(args->keys->key[0]), "%s:%s",
+ "frr-zebra",
+ zebra_afi_safi_value2identity(zrt->afi, zrt->safi));
+ snprintfrr(args->keys->key[1], sizeof(args->keys->key[1]), "%" PRIu32,
+ zrt->tableid);
+
return NB_OK;
}
-const void *lib_vrf_ribs_rib_lookup_entry(struct nb_cb_lookup_entry_args *args)
+const void *
+lib_vrf_zebra_ribs_rib_lookup_entry(struct nb_cb_lookup_entry_args *args)
{
- /* TODO: implement me. */
- return NULL;
+ struct vrf *vrf = (struct vrf *)args->parent_list_entry;
+ struct zebra_vrf *zvrf;
+ afi_t afi;
+ safi_t safi;
+ uint32_t table_id = 0;
+
+ zvrf = zebra_vrf_lookup_by_id(vrf->vrf_id);
+
+ zebra_afi_safi_identity2value(args->keys->key[0], &afi, &safi);
+ table_id = yang_str2uint32(args->keys->key[1]);
+ /* table_id 0 assume vrf's table_id. */
+ if (!table_id)
+ table_id = zvrf->table_id;
+
+ return zebra_router_find_zrt(zvrf, table_id, afi, safi);
}
/*
- * XPath: /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route
+ * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route
*/
-const void *lib_vrf_ribs_rib_route_get_next(struct nb_cb_get_next_args *args)
-{
- /* TODO: implement me. */
- return NULL;
+const void *
+lib_vrf_zebra_ribs_rib_route_get_next(struct nb_cb_get_next_args *args)
+{
+ const struct zebra_router_table *zrt = args->parent_list_entry;
+ struct route_node *rn = (struct route_node *)args->list_entry;
+
+ if (args->list_entry == NULL)
+ rn = route_top(zrt->table);
+ else
+ rn = srcdest_route_next((struct route_node *)rn);
+ /* Optimization: skip empty route nodes. */
+ while (rn && rn->info == NULL)
+ rn = route_next(rn);
+
+ /* Skip link-local routes. */
+ if (rn && rn->p.family == AF_INET6
+ && IN6_IS_ADDR_LINKLOCAL(&rn->p.u.prefix6))
+ return NULL;
+
+ return rn;
}
-int lib_vrf_ribs_rib_route_get_keys(struct nb_cb_get_keys_args *args)
+int lib_vrf_zebra_ribs_rib_route_get_keys(struct nb_cb_get_keys_args *args)
{
- /* TODO: implement me. */
+ const struct route_node *rn = args->list_entry;
+
+ args->keys->num = 1;
+ prefix2str(&rn->p, args->keys->key[0], sizeof(args->keys->key[0]));
+
return NB_OK;
}
const void *
-lib_vrf_ribs_rib_route_lookup_entry(struct nb_cb_lookup_entry_args *args)
+lib_vrf_zebra_ribs_rib_route_lookup_entry(struct nb_cb_lookup_entry_args *args)
{
- /* TODO: implement me. */
- return NULL;
+ const struct zebra_router_table *zrt = args->parent_list_entry;
+ struct prefix p;
+ struct route_node *rn;
+
+ yang_str2prefix(args->keys->key[0], &p);
+
+ rn = route_node_lookup(zrt->table, &p);
+
+ if (!rn)
+ return NULL;
+
+ route_unlock_node(rn);
+
+ return rn;
}
/*
- * XPath: /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/prefix
+ * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/prefix
*/
struct yang_data *
-lib_vrf_ribs_rib_route_prefix_get_elem(struct nb_cb_get_elem_args *args)
+lib_vrf_zebra_ribs_rib_route_prefix_get_elem(struct nb_cb_get_elem_args *args)
{
- /* TODO: implement me. */
- return NULL;
+ const struct route_node *rn = args->list_entry;
+
+ return yang_data_new_prefix(args->xpath, &rn->p);
}
/*
- * XPath: /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry
+ * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry
*/
-const void *
-lib_vrf_ribs_rib_route_route_entry_get_next(struct nb_cb_get_next_args *args)
+const void *lib_vrf_zebra_ribs_rib_route_route_entry_get_next(
+ struct nb_cb_get_next_args *args)
{
- /* TODO: implement me. */
- return NULL;
+ struct route_entry *re = (struct route_entry *)args->list_entry;
+ struct route_node *rn = (struct route_node *)args->parent_list_entry;
+
+ if (args->list_entry == NULL)
+ RNODE_FIRST_RE(rn, re);
+ else
+ RNODE_NEXT_RE(rn, re);
+
+ return re;
}
-int lib_vrf_ribs_rib_route_route_entry_get_keys(
+int lib_vrf_zebra_ribs_rib_route_route_entry_get_keys(
struct nb_cb_get_keys_args *args)
{
- /* TODO: implement me. */
+ struct route_entry *re = (struct route_entry *)args->list_entry;
+
+ args->keys->num = 1;
+
+ strlcpy(args->keys->key[0], zebra_route_string(re->type),
+ sizeof(args->keys->key[0]));
+
return NB_OK;
}
-const void *lib_vrf_ribs_rib_route_route_entry_lookup_entry(
+const void *lib_vrf_zebra_ribs_rib_route_route_entry_lookup_entry(
struct nb_cb_lookup_entry_args *args)
{
- /* TODO: implement me. */
+ struct route_node *rn = (struct route_node *)args->parent_list_entry;
+ struct route_entry *re = NULL;
+ int proto_type = 0;
+ afi_t afi;
+
+ afi = family2afi(rn->p.family);
+ proto_type = proto_redistnum(afi, args->keys->key[0]);
+
+ RNODE_FOREACH_RE (rn, re) {
+ if (proto_type == re->type)
+ return re;
+ }
+
return NULL;
}
/*
- * XPath: /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/protocol
+ * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/protocol
*/
-struct yang_data *lib_vrf_ribs_rib_route_route_entry_protocol_get_elem(
+struct yang_data *lib_vrf_zebra_ribs_rib_route_route_entry_protocol_get_elem(
struct nb_cb_get_elem_args *args)
{
- /* TODO: implement me. */
- return NULL;
+ struct route_entry *re = (struct route_entry *)args->list_entry;
+
+ return yang_data_new_enum(args->xpath, re->type);
}
/*
- * XPath: /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/instance
+ * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/instance
*/
-struct yang_data *lib_vrf_ribs_rib_route_route_entry_instance_get_elem(
+struct yang_data *lib_vrf_zebra_ribs_rib_route_route_entry_instance_get_elem(
struct nb_cb_get_elem_args *args)
{
- /* TODO: implement me. */
+ struct route_entry *re = (struct route_entry *)args->list_entry;
+
+ if (re->instance)
+ return yang_data_new_uint16(args->xpath, re->instance);
+
return NULL;
}
/*
- * XPath: /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/distance
+ * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/distance
*/
-struct yang_data *lib_vrf_ribs_rib_route_route_entry_distance_get_elem(
+struct yang_data *lib_vrf_zebra_ribs_rib_route_route_entry_distance_get_elem(
struct nb_cb_get_elem_args *args)
{
- /* TODO: implement me. */
- return NULL;
+ struct route_entry *re = (struct route_entry *)args->list_entry;
+
+ return yang_data_new_uint8(args->xpath, re->distance);
}
/*
- * XPath: /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/metric
+ * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/metric
*/
-struct yang_data *lib_vrf_ribs_rib_route_route_entry_metric_get_elem(
+struct yang_data *lib_vrf_zebra_ribs_rib_route_route_entry_metric_get_elem(
struct nb_cb_get_elem_args *args)
{
- /* TODO: implement me. */
- return NULL;
+ struct route_entry *re = (struct route_entry *)args->list_entry;
+
+ return yang_data_new_uint32(args->xpath, re->metric);
}
/*
- * XPath: /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/tag
+ * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/tag
*/
-struct yang_data *lib_vrf_ribs_rib_route_route_entry_tag_get_elem(
+struct yang_data *lib_vrf_zebra_ribs_rib_route_route_entry_tag_get_elem(
struct nb_cb_get_elem_args *args)
{
- /* TODO: implement me. */
+ struct route_entry *re = (struct route_entry *)args->list_entry;
+
+ if (re->tag)
+ return yang_data_new_uint32(args->xpath, re->tag);
+
return NULL;
}
/*
- * XPath: /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/selected
+ * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/selected
*/
-struct yang_data *lib_vrf_ribs_rib_route_route_entry_selected_get_elem(
+struct yang_data *lib_vrf_zebra_ribs_rib_route_route_entry_selected_get_elem(
struct nb_cb_get_elem_args *args)
{
- /* TODO: implement me. */
+ struct route_entry *re = (struct route_entry *)args->list_entry;
+
+ if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
+ return yang_data_new_empty(args->xpath);
+
return NULL;
}
/*
- * XPath: /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/installed
+ * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/installed
*/
-struct yang_data *lib_vrf_ribs_rib_route_route_entry_installed_get_elem(
+struct yang_data *lib_vrf_zebra_ribs_rib_route_route_entry_installed_get_elem(
struct nb_cb_get_elem_args *args)
{
- /* TODO: implement me. */
+ struct route_entry *re = (struct route_entry *)args->list_entry;
+
+ if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED))
+ return yang_data_new_empty(args->xpath);
+
return NULL;
}
/*
- * XPath: /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/failed
+ * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/failed
*/
-struct yang_data *lib_vrf_ribs_rib_route_route_entry_failed_get_elem(
+struct yang_data *lib_vrf_zebra_ribs_rib_route_route_entry_failed_get_elem(
struct nb_cb_get_elem_args *args)
{
- /* TODO: implement me. */
+ struct route_entry *re = (struct route_entry *)args->list_entry;
+
+ if (CHECK_FLAG(re->status, ROUTE_ENTRY_FAILED))
+ return yang_data_new_empty(args->xpath);
+
return NULL;
}
/*
- * XPath: /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/queued
+ * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/queued
*/
-struct yang_data *lib_vrf_ribs_rib_route_route_entry_queued_get_elem(
+struct yang_data *lib_vrf_zebra_ribs_rib_route_route_entry_queued_get_elem(
struct nb_cb_get_elem_args *args)
{
- /* TODO: implement me. */
+ struct route_entry *re = (struct route_entry *)args->list_entry;
+
+ if (CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED))
+ return yang_data_new_empty(args->xpath);
+
return NULL;
}
/*
- * XPath: /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/internal-flags
+ * XPath:
+ * /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/internal-flags
*/
-struct yang_data *lib_vrf_ribs_rib_route_route_entry_internal_flags_get_elem(
+struct yang_data *
+lib_vrf_zebra_ribs_rib_route_route_entry_internal_flags_get_elem(
struct nb_cb_get_elem_args *args)
{
- /* TODO: implement me. */
+ struct route_entry *re = (struct route_entry *)args->list_entry;
+
+ if (re->flags)
+ return yang_data_new_int32(args->xpath, re->flags);
+
return NULL;
}
/*
- * XPath: /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/internal-status
+ * XPath:
+ * /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/internal-status
*/
-struct yang_data *lib_vrf_ribs_rib_route_route_entry_internal_status_get_elem(
+struct yang_data *
+lib_vrf_zebra_ribs_rib_route_route_entry_internal_status_get_elem(
struct nb_cb_get_elem_args *args)
{
- /* TODO: implement me. */
+ struct route_entry *re = (struct route_entry *)args->list_entry;
+
+ if (re->status)
+ return yang_data_new_int32(args->xpath, re->status);
+
return NULL;
}
/*
- * XPath: /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/uptime
+ * XPath: /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/uptime
*/
-struct yang_data *lib_vrf_ribs_rib_route_route_entry_uptime_get_elem(
+struct yang_data *lib_vrf_zebra_ribs_rib_route_route_entry_uptime_get_elem(
struct nb_cb_get_elem_args *args)
{
- /* TODO: implement me. */
- return NULL;
+ struct route_entry *re = (struct route_entry *)args->list_entry;
+
+ return yang_data_new_date_and_time(args->xpath, re->uptime);
}
/*
- * XPath: /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group
+ * XPath:
+ * /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group
*/
-const void *lib_vrf_ribs_rib_route_route_entry_nexthop_group_get_next(
+const void *lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_get_next(
struct nb_cb_get_next_args *args)
{
- /* TODO: implement me. */
+ struct route_entry *re = (struct route_entry *)args->parent_list_entry;
+ struct nhg_hash_entry *nhe = (struct nhg_hash_entry *)args->list_entry;
+
+ if (nhe == NULL) {
+ nhe = re->nhe;
+ return nhe;
+ }
return NULL;
}
-int lib_vrf_ribs_rib_route_route_entry_nexthop_group_get_keys(
+int lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_get_keys(
struct nb_cb_get_keys_args *args)
{
- /* TODO: implement me. */
+ struct nhg_hash_entry *nhe = (struct nhg_hash_entry *)args->list_entry;
+
+ args->keys->num = 1;
+ snprintfrr(args->keys->key[0], sizeof(args->keys->key[0]), "%" PRIu32,
+ nhe->id);
+
return NB_OK;
}
-const void *lib_vrf_ribs_rib_route_route_entry_nexthop_group_lookup_entry(
+const void *lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_lookup_entry(
struct nb_cb_lookup_entry_args *args)
{
- /* TODO: implement me. */
- return NULL;
+ struct route_entry *re = (struct route_entry *)args->parent_list_entry;
+
+ return re->nhe;
}
/*
* XPath:
- * /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/name
+ * /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/name
*/
struct yang_data *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_name_get_elem(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_name_get_elem(
struct nb_cb_get_elem_args *args)
{
- /* TODO: implement me. */
- return NULL;
+ struct nhg_hash_entry *nhe = (struct nhg_hash_entry *)args->list_entry;
+ char name[20] = {'\0'};
+
+ snprintfrr(name, sizeof(name), "%" PRIu32, nhe->id);
+
+ return yang_data_new_string(args->xpath, name);
}
/*
* XPath:
- * /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop
+ * /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop
*/
const void *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_get_next(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_get_next(
struct nb_cb_get_next_args *args)
{
- /* TODO: implement me. */
- return NULL;
+ struct nexthop *nexthop = (struct nexthop *)args->list_entry;
+ struct nhg_hash_entry *nhe =
+ (struct nhg_hash_entry *)args->parent_list_entry;
+
+ if (args->list_entry == NULL)
+ nexthop = nhe->nhg.nexthop;
+ else
+ nexthop = nexthop_next(nexthop);
+
+ return nexthop;
}
-int lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_get_keys(
+int lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_get_keys(
struct nb_cb_get_keys_args *args)
{
- /* TODO: implement me. */
+ struct nexthop *nexthop = (struct nexthop *)args->list_entry;
+
+ args->keys->num = 3;
+
+ strlcpy(args->keys->key[0], yang_nexthop_type2str(nexthop->type),
+ sizeof(args->keys->key[0]));
+
+ switch (nexthop->type) {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ snprintfrr(args->keys->key[1], sizeof(args->keys->key[1]),
+ "%pI4", &nexthop->gate.ipv4);
+ if (nexthop->ifindex)
+ strlcpy(args->keys->key[2],
+ ifindex2ifname(nexthop->ifindex,
+ nexthop->vrf_id),
+ sizeof(args->keys->key[2]));
+ else
+ /* no ifindex */
+ strlcpy(args->keys->key[2], " ",
+ sizeof(args->keys->key[2]));
+
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ snprintfrr(args->keys->key[1], sizeof(args->keys->key[1]),
+ "%pI6", &nexthop->gate.ipv6);
+
+ if (nexthop->ifindex)
+ strlcpy(args->keys->key[2],
+ ifindex2ifname(nexthop->ifindex,
+ nexthop->vrf_id),
+ sizeof(args->keys->key[2]));
+ else
+ /* no ifindex */
+ strlcpy(args->keys->key[2], " ",
+ sizeof(args->keys->key[2]));
+
+ break;
+ case NEXTHOP_TYPE_IFINDEX:
+ strlcpy(args->keys->key[1], "", sizeof(args->keys->key[1]));
+ strlcpy(args->keys->key[2],
+ ifindex2ifname(nexthop->ifindex, nexthop->vrf_id),
+ sizeof(args->keys->key[2]));
+
+ break;
+ case NEXTHOP_TYPE_BLACKHOLE:
+ /* Gateway IP */
+ strlcpy(args->keys->key[1], "", sizeof(args->keys->key[1]));
+ strlcpy(args->keys->key[2], " ", sizeof(args->keys->key[2]));
+ break;
+ default:
+ break;
+ }
+
return NB_OK;
}
const void *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_lookup_entry(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_lookup_entry(
struct nb_cb_lookup_entry_args *args)
{
- /* TODO: implement me. */
+ struct nhg_hash_entry *nhe;
+ struct nexthop nexthop_lookup = {};
+ struct nexthop *nexthop;
+ const char *nh_type_str;
+
+ nhe = (struct nhg_hash_entry *)args->parent_list_entry;
+ nexthop_lookup.vrf_id = nhe->vrf_id;
+
+ /*
+ * Get nexthop type.
+ * TODO: use yang_str2enum() instead.
+ */
+ nh_type_str = args->keys->key[0];
+ if (strmatch(nh_type_str, "ifindex"))
+ nexthop_lookup.type = NEXTHOP_TYPE_IFINDEX;
+ else if (strmatch(nh_type_str, "ip4"))
+ nexthop_lookup.type = NEXTHOP_TYPE_IPV4;
+ else if (strmatch(nh_type_str, "ip4-ifindex"))
+ nexthop_lookup.type = NEXTHOP_TYPE_IPV4_IFINDEX;
+ else if (strmatch(nh_type_str, "ip6"))
+ nexthop_lookup.type = NEXTHOP_TYPE_IPV6;
+ else if (strmatch(nh_type_str, "ip6-ifindex"))
+ nexthop_lookup.type = NEXTHOP_TYPE_IPV6_IFINDEX;
+ else if (strmatch(nh_type_str, "blackhole"))
+ nexthop_lookup.type = NEXTHOP_TYPE_BLACKHOLE;
+ else
+ /* unexpected */
+ return NULL;
+
+ /* Get nexthop address. */
+ switch (nexthop_lookup.type) {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ yang_str2ipv4(args->keys->key[1], &nexthop_lookup.gate.ipv4);
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ yang_str2ipv6(args->keys->key[1], &nexthop_lookup.gate.ipv6);
+ break;
+ case NEXTHOP_TYPE_IFINDEX:
+ case NEXTHOP_TYPE_BLACKHOLE:
+ break;
+ }
+
+ /* Get nexthop interface. */
+ switch (nexthop_lookup.type) {
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ case NEXTHOP_TYPE_IFINDEX:
+ nexthop_lookup.ifindex =
+ ifname2ifindex(args->keys->key[2], nhe->vrf_id);
+ break;
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_BLACKHOLE:
+ break;
+ }
+
+ /* Lookup requested nexthop (ignore weight and metric). */
+ for (ALL_NEXTHOPS(nhe->nhg, nexthop)) {
+ nexthop_lookup.weight = nexthop->weight;
+ nexthop_lookup.src = nexthop->src;
+ if (nexthop_same_no_labels(&nexthop_lookup, nexthop))
+ return nexthop;
+ }
+
return NULL;
}
/*
* XPath:
- * /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/nh-type
+ * /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/nh-type
*/
struct yang_data *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_nh_type_get_elem(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_nh_type_get_elem(
struct nb_cb_get_elem_args *args)
{
- /* TODO: implement me. */
+ struct nexthop *nexthop = (struct nexthop *)args->list_entry;
+
+ switch (nexthop->type) {
+ case NEXTHOP_TYPE_IFINDEX:
+ return yang_data_new_string(args->xpath, "ifindex");
+ break;
+ case NEXTHOP_TYPE_IPV4:
+ return yang_data_new_string(args->xpath, "ip4");
+ break;
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ return yang_data_new_string(args->xpath, "ip4-ifindex");
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ return yang_data_new_string(args->xpath, "ip6");
+ break;
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ return yang_data_new_string(args->xpath, "ip6-ifindex");
+ break;
+ default:
+ break;
+ }
+
return NULL;
}
/*
* XPath:
- * /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/vrf
+ * /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/vrf
*/
struct yang_data *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_vrf_get_elem(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_vrf_get_elem(
struct nb_cb_get_elem_args *args)
{
- /* TODO: implement me. */
- return NULL;
+ struct nexthop *nexthop = (struct nexthop *)args->list_entry;
+
+ return yang_data_new_string(args->xpath,
+ vrf_id_to_name(nexthop->vrf_id));
}
/*
* XPath:
- * /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/gateway
+ * /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/gateway
*/
struct yang_data *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_gateway_get_elem(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_gateway_get_elem(
struct nb_cb_get_elem_args *args)
{
- /* TODO: implement me. */
- return NULL;
+ struct nexthop *nexthop = (struct nexthop *)args->list_entry;
+ struct ipaddr addr;
+
+ switch (nexthop->type) {
+ case NEXTHOP_TYPE_IPV4:
+ case NEXTHOP_TYPE_IPV4_IFINDEX:
+ addr.ipa_type = IPADDR_V4;
+ memcpy(&addr.ipaddr_v4, &(nexthop->gate.ipv4),
+ sizeof(struct in_addr));
+ break;
+ case NEXTHOP_TYPE_IPV6:
+ case NEXTHOP_TYPE_IPV6_IFINDEX:
+ addr.ipa_type = IPADDR_V6;
+ memcpy(&addr.ipaddr_v6, &(nexthop->gate.ipv6),
+ sizeof(struct in6_addr));
+ break;
+ case NEXTHOP_TYPE_BLACKHOLE:
+ case NEXTHOP_TYPE_IFINDEX:
+ /* No addr here */
+ return yang_data_new_string(args->xpath, "");
+ break;
+ default:
+ break;
+ }
+
+ return yang_data_new_ip(args->xpath, &addr);
}
/*
* XPath:
- * /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/interface
+ * /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/interface
*/
struct yang_data *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_interface_get_elem(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_interface_get_elem(
struct nb_cb_get_elem_args *args)
{
- /* TODO: implement me. */
+ struct nexthop *nexthop = (struct nexthop *)args->list_entry;
+
+ if (nexthop->ifindex)
+ return yang_data_new_string(
+ args->xpath,
+ ifindex2ifname(nexthop->ifindex, nexthop->vrf_id));
+
return NULL;
}
/*
* XPath:
- * /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/bh-type
+ * /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/bh-type
*/
struct yang_data *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_bh_type_get_elem(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_bh_type_get_elem(
struct nb_cb_get_elem_args *args)
{
- /* TODO: implement me. */
- return NULL;
+ struct nexthop *nexthop = (struct nexthop *)args->list_entry;
+ const char *type_str = "";
+
+ if (nexthop->type != NEXTHOP_TYPE_BLACKHOLE)
+ return NULL;
+
+ switch (nexthop->bh_type) {
+ case BLACKHOLE_NULL:
+ type_str = "null";
+ break;
+ case BLACKHOLE_REJECT:
+ type_str = "reject";
+ break;
+ case BLACKHOLE_ADMINPROHIB:
+ type_str = "prohibited";
+ break;
+ case BLACKHOLE_UNSPEC:
+ type_str = "unspec";
+ break;
+ }
+
+ return yang_data_new_string(args->xpath, type_str);
}
/*
* XPath:
- * /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/onlink
+ * /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/onlink
*/
struct yang_data *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_onlink_get_elem(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_onlink_get_elem(
struct nb_cb_get_elem_args *args)
{
- /* TODO: implement me. */
+ struct nexthop *nexthop = (struct nexthop *)args->list_entry;
+
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK))
+ return yang_data_new_bool(args->xpath, true);
+
return NULL;
}
/*
* XPath:
- * /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/mpls-label-stack/entry
+ * /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/mpls-label-stack/entry
*/
const void *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_get_next(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_get_next(
struct nb_cb_get_next_args *args)
{
/* TODO: implement me. */
return NULL;
}
-int lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_get_keys(
+int lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_get_keys(
struct nb_cb_get_keys_args *args)
{
/* TODO: implement me. */
@@ -496,7 +864,7 @@ int lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_l
}
const void *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_lookup_entry(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_lookup_entry(
struct nb_cb_lookup_entry_args *args)
{
/* TODO: implement me. */
@@ -505,10 +873,10 @@ lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label
/*
* XPath:
- * /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/mpls-label-stack/entry/id
+ * /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/mpls-label-stack/entry/id
*/
struct yang_data *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_id_get_elem(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_id_get_elem(
struct nb_cb_get_elem_args *args)
{
/* TODO: implement me. */
@@ -517,10 +885,10 @@ lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label
/*
* XPath:
- * /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/mpls-label-stack/entry/label
+ * /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/mpls-label-stack/entry/label
*/
struct yang_data *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_label_get_elem(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_label_get_elem(
struct nb_cb_get_elem_args *args)
{
/* TODO: implement me. */
@@ -529,10 +897,10 @@ lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label
/*
* XPath:
- * /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/mpls-label-stack/entry/ttl
+ * /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/mpls-label-stack/entry/ttl
*/
struct yang_data *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_ttl_get_elem(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_ttl_get_elem(
struct nb_cb_get_elem_args *args)
{
/* TODO: implement me. */
@@ -541,10 +909,10 @@ lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label
/*
* XPath:
- * /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/mpls-label-stack/entry/traffic-class
+ * /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/mpls-label-stack/entry/traffic-class
*/
struct yang_data *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_traffic_class_get_elem(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label_stack_entry_traffic_class_get_elem(
struct nb_cb_get_elem_args *args)
{
/* TODO: implement me. */
@@ -553,60 +921,80 @@ lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_mpls_label
/*
* XPath:
- * /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/duplicate
+ * /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/duplicate
*/
struct yang_data *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_duplicate_get_elem(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_duplicate_get_elem(
struct nb_cb_get_elem_args *args)
{
- /* TODO: implement me. */
+ struct nexthop *nexthop = (struct nexthop *)args->list_entry;
+
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE))
+ return yang_data_new_empty(args->xpath);
+
return NULL;
}
/*
* XPath:
- * /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/recursive
+ * /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/recursive
*/
struct yang_data *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_recursive_get_elem(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_recursive_get_elem(
struct nb_cb_get_elem_args *args)
{
- /* TODO: implement me. */
+ struct nexthop *nexthop = (struct nexthop *)args->list_entry;
+
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
+ return yang_data_new_empty(args->xpath);
+
return NULL;
}
/*
* XPath:
- * /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/active
+ * /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/active
*/
struct yang_data *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_active_get_elem(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_active_get_elem(
struct nb_cb_get_elem_args *args)
{
- /* TODO: implement me. */
+ struct nexthop *nexthop = (struct nexthop *)args->list_entry;
+
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE))
+ return yang_data_new_empty(args->xpath);
+
return NULL;
}
/*
* XPath:
- * /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/fib
+ * /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/fib
*/
struct yang_data *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_fib_get_elem(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_fib_get_elem(
struct nb_cb_get_elem_args *args)
{
- /* TODO: implement me. */
+ struct nexthop *nexthop = (struct nexthop *)args->list_entry;
+
+ if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))
+ return yang_data_new_empty(args->xpath);
+
return NULL;
}
/*
* XPath:
- * /frr-vrf:lib/vrf/frr-zebra:ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/weight
+ * /frr-vrf:lib/vrf/frr-zebra:zebra/ribs/rib/route/route-entry/nexthop-group/frr-nexthops/nexthop/weight
*/
struct yang_data *
-lib_vrf_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_weight_get_elem(
+lib_vrf_zebra_ribs_rib_route_route_entry_nexthop_group_frr_nexthops_nexthop_weight_get_elem(
struct nb_cb_get_elem_args *args)
{
- /* TODO: implement me. */
+ struct nexthop *nexthop = (struct nexthop *)args->list_entry;
+
+ if (nexthop->weight)
+ return yang_data_new_uint8(args->xpath, nexthop->weight);
+
return NULL;
}
diff --git a/zebra/zebra_netns_id.c b/zebra/zebra_netns_id.c
index 77a9a7c368..0d86421b9e 100644
--- a/zebra/zebra_netns_id.c
+++ b/zebra/zebra_netns_id.c
@@ -159,27 +159,34 @@ static ns_id_t extract_nsid(struct nlmsghdr *nlh, char *buf)
return ns_id;
}
-ns_id_t zebra_ns_id_get(const char *netnspath)
+/* fd_param = -1 is ignored.
+ * netnspath set to null is ignored.
+ * one of the 2 params is mandatory. netnspath is looked in priority
+ */
+ns_id_t zebra_ns_id_get(const char *netnspath, int fd_param)
{
int ns_id = -1;
struct sockaddr_nl snl;
- int fd, sock, ret;
+ int fd = -1, sock, ret;
unsigned int seq;
ns_id_t return_nsid = NS_UNKNOWN;
/* netns path check */
- if (!netnspath)
- return NS_UNKNOWN;
- fd = open(netnspath, O_RDONLY);
- if (fd == -1)
+ if (!netnspath && fd_param == -1)
return NS_UNKNOWN;
-
+ if (netnspath) {
+ fd = open(netnspath, O_RDONLY);
+ if (fd == -1)
+ return NS_UNKNOWN;
+ } else if (fd_param != -1)
+ fd = fd_param;
/* netlink socket */
sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
if (sock < 0) {
flog_err_sys(EC_LIB_SOCKET, "netlink( %u) socket() error: %s",
sock, safe_strerror(errno));
- close(fd);
+ if (fd_param == -1)
+ close(fd);
return NS_UNKNOWN;
}
memset(&snl, 0, sizeof(snl));
@@ -192,7 +199,8 @@ ns_id_t zebra_ns_id_get(const char *netnspath)
"netlink( %u) socket() bind error: %s", sock,
safe_strerror(errno));
close(sock);
- close(fd);
+ if (fd_param == -1)
+ close(fd);
return NS_UNKNOWN;
}
@@ -214,7 +222,8 @@ ns_id_t zebra_ns_id_get(const char *netnspath)
ret = send_receive(sock, nlh, seq, buf);
if (ret < 0) {
close(sock);
- close(fd);
+ if (fd_param == -1)
+ close(fd);
return NS_UNKNOWN;
}
nlh = (struct nlmsghdr *)buf;
@@ -258,7 +267,8 @@ ns_id_t zebra_ns_id_get(const char *netnspath)
"netlink( %u) recvfrom() error 2 when reading: %s",
fd, safe_strerror(errno));
close(sock);
- close(fd);
+ if (fd_param == -1)
+ close(fd);
if (errno == ENOTSUP) {
zlog_debug("NEWNSID locally generated");
return zebra_ns_id_get_fallback(netnspath);
@@ -278,7 +288,8 @@ ns_id_t zebra_ns_id_get(const char *netnspath)
ret = send_receive(sock, nlh, seq, buf);
if (ret < 0) {
close(sock);
- close(fd);
+ if (fd_param == -1)
+ close(fd);
return NS_UNKNOWN;
}
nlh = (struct nlmsghdr *)buf;
@@ -309,16 +320,18 @@ ns_id_t zebra_ns_id_get(const char *netnspath)
} while (len != 0 && ret == 0);
}
- close(fd);
+ if (fd_param == -1)
+ close(fd);
close(sock);
return return_nsid;
}
#else
-ns_id_t zebra_ns_id_get(const char *netnspath)
+ns_id_t zebra_ns_id_get(const char *netnspath, int fd __attribute__ ((unused)))
{
return zebra_ns_id_get_fallback(netnspath);
}
+
#endif /* ! defined(HAVE_NETLINK) */
#ifdef HAVE_NETNS
@@ -354,7 +367,7 @@ ns_id_t zebra_ns_id_get_default(void)
return NS_DEFAULT_INTERNAL;
}
close(fd);
- return zebra_ns_id_get((char *)NS_DEFAULT_NAME);
+ return zebra_ns_id_get((char *)NS_DEFAULT_NAME, -1);
#else /* HAVE_NETNS */
return NS_DEFAULT_INTERNAL;
#endif /* !HAVE_NETNS */
diff --git a/zebra/zebra_netns_id.h b/zebra/zebra_netns_id.h
index 7a5f6851f4..dd9eab18e0 100644
--- a/zebra/zebra_netns_id.h
+++ b/zebra/zebra_netns_id.h
@@ -24,7 +24,7 @@
extern "C" {
#endif
-extern ns_id_t zebra_ns_id_get(const char *netnspath);
+extern ns_id_t zebra_ns_id_get(const char *netnspath, int fd);
extern ns_id_t zebra_ns_id_get_default(void);
#ifdef __cplusplus
diff --git a/zebra/zebra_netns_notify.c b/zebra/zebra_netns_notify.c
index c5d11f1837..72e4fd0055 100644
--- a/zebra/zebra_netns_notify.c
+++ b/zebra/zebra_netns_notify.c
@@ -72,13 +72,14 @@ static void zebra_ns_notify_create_context_from_entry_name(const char *name)
char *netnspath = ns_netns_pathname(NULL, name);
struct vrf *vrf;
int ret;
- ns_id_t ns_id, ns_id_external;
+ ns_id_t ns_id, ns_id_external, ns_id_relative = NS_UNKNOWN;
+ struct ns *default_ns;
if (netnspath == NULL)
return;
frr_with_privs(&zserv_privs) {
- ns_id = zebra_ns_id_get(netnspath);
+ ns_id = zebra_ns_id_get(netnspath, -1);
}
if (ns_id == NS_UNKNOWN)
return;
@@ -97,9 +98,21 @@ static void zebra_ns_notify_create_context_from_entry_name(const char *name)
ns_map_nsid_with_external(ns_id, false);
return;
}
+
+ default_ns = ns_get_default();
+
+ /* force kernel ns_id creation in that new vrf */
+ frr_with_privs(&zserv_privs) {
+ ns_switch_to_netns(netnspath);
+ ns_id_relative = zebra_ns_id_get(NULL, default_ns->fd);
+ ns_switchback_to_initial();
+ }
+
frr_with_privs(&zserv_privs) {
ret = vrf_netns_handler_create(NULL, vrf, netnspath,
- ns_id_external, ns_id);
+ ns_id_external,
+ ns_id,
+ ns_id_relative);
}
if (ret != CMD_SUCCESS) {
flog_warn(EC_ZEBRA_NS_VRF_CREATION_FAILED,
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index fc5128b678..1ac18c6fdd 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -1681,17 +1681,37 @@ static void nexthop_set_resolved(afi_t afi, const struct nexthop *newhop,
/* Copy labels of the resolved route and the parent resolving to it */
if (newhop->nh_label) {
- for (i = 0; i < newhop->nh_label->num_labels; i++)
+ for (i = 0; i < newhop->nh_label->num_labels; i++) {
+ /* Be a bit picky about overrunning the local array */
+ if (num_labels >= MPLS_MAX_LABELS) {
+ if (IS_ZEBRA_DEBUG_NHG || IS_ZEBRA_DEBUG_RIB)
+ zlog_debug("%s: too many labels in newhop %pNHv",
+ __func__, newhop);
+ break;
+ }
labels[num_labels++] = newhop->nh_label->label[i];
+ }
+ /* Use the "outer" type */
label_type = newhop->nh_label_type;
}
if (nexthop->nh_label) {
- for (i = 0; i < nexthop->nh_label->num_labels; i++)
+ for (i = 0; i < nexthop->nh_label->num_labels; i++) {
+ /* Be a bit picky about overrunning the local array */
+ if (num_labels >= MPLS_MAX_LABELS) {
+ if (IS_ZEBRA_DEBUG_NHG || IS_ZEBRA_DEBUG_RIB)
+ zlog_debug("%s: too many labels in nexthop %pNHv",
+ __func__, nexthop);
+ break;
+ }
labels[num_labels++] = nexthop->nh_label->label[i];
+ }
- /* If the parent has labels, use its type */
- label_type = nexthop->nh_label_type;
+ /* If the parent has labels, use its type if
+ * we don't already have one.
+ */
+ if (label_type == ZEBRA_LSP_NONE)
+ label_type = nexthop->nh_label_type;
}
if (num_labels)
@@ -1776,33 +1796,24 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
return 1;
/*
- * Check to see if we should trust the passed in information
- * for UNNUMBERED interfaces as that we won't find the GW
- * address in the routing table.
- * This check should suffice to handle IPv4 or IPv6 routes
- * sourced from EVPN routes which are installed with the
- * next hop as the remote VTEP IP.
+ * If the nexthop has been marked as 'onlink' we just need to make
+ * sure the nexthop's interface is known and is operational.
*/
if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ONLINK)) {
ifp = if_lookup_by_index(nexthop->ifindex, nexthop->vrf_id);
if (!ifp) {
- if (IS_ZEBRA_DEBUG_RIB_DETAILED)
- zlog_debug(
- " %s: Onlink and interface: %u[%u] does not exist",
- __func__, nexthop->ifindex,
- nexthop->vrf_id);
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("nexthop %pNHv marked onlink but nhif %u doesn't exist",
+ nexthop, nexthop->ifindex);
return 0;
}
-
- if (if_is_operative(ifp))
- return 1;
- else {
- if (IS_ZEBRA_DEBUG_RIB_DETAILED)
- zlog_debug(
- " %s: Onlink and interface %s is not operative",
- __func__, ifp->name);
+ if (!if_is_operative(ifp)) {
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("nexthop %pNHv marked onlink but nhif %s is not operational",
+ nexthop, ifp->name);
return 0;
}
+ return 1;
}
if ((top->p.family == AF_INET && top->p.prefixlen == 32
@@ -2092,7 +2103,7 @@ static unsigned nexthop_active_check(struct route_node *rn,
* in every case.
*/
if (!family) {
- rib_table_info_t *info;
+ struct rib_table_info *info;
info = srcdest_rnode_table_info(rn);
family = info->afi;
diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h
index 5792584d0f..785ce20b75 100644
--- a/zebra/zebra_nhg.h
+++ b/zebra/zebra_nhg.h
@@ -117,6 +117,10 @@ struct nhg_hash_entry {
*/
#define NEXTHOP_GROUP_BACKUP (1 << 5)
+/*
+ * Track FPM installation status..
+ */
+#define NEXTHOP_GROUP_FPM (1 << 6)
};
/* Was this one we created, either this session or previously? */
diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c
index 4e51437337..6462daf687 100644
--- a/zebra/zebra_ns.c
+++ b/zebra/zebra_ns.c
@@ -153,20 +153,25 @@ static int zebra_ns_disable_internal(struct zebra_ns *zns, bool complete)
/* During zebra shutdown, do partial cleanup while the async dataplane
* is still running.
*/
-int zebra_ns_early_shutdown(struct ns *ns)
+int zebra_ns_early_shutdown(struct ns *ns,
+ void *param_in __attribute__((unused)),
+ void **param_out __attribute__((unused)))
{
struct zebra_ns *zns = ns->info;
if (zns == NULL)
return 0;
- return zebra_ns_disable_internal(zns, false);
+ zebra_ns_disable_internal(zns, false);
+ return NS_WALK_CONTINUE;
}
/* During zebra shutdown, do final cleanup
* after all dataplane work is complete.
*/
-int zebra_ns_final_shutdown(struct ns *ns)
+int zebra_ns_final_shutdown(struct ns *ns,
+ void *param_in __attribute__((unused)),
+ void **param_out __attribute__((unused)))
{
struct zebra_ns *zns = ns->info;
@@ -175,7 +180,7 @@ int zebra_ns_final_shutdown(struct ns *ns)
kernel_terminate(zns, true);
- return 0;
+ return NS_WALK_CONTINUE;
}
int zebra_ns_init(const char *optional_default_name)
@@ -183,12 +188,16 @@ int zebra_ns_init(const char *optional_default_name)
struct ns *default_ns;
ns_id_t ns_id;
ns_id_t ns_id_external;
+ struct ns *ns;
frr_with_privs(&zserv_privs) {
ns_id = zebra_ns_id_get_default();
}
ns_id_external = ns_map_nsid_with_external(ns_id, true);
ns_init_management(ns_id_external, ns_id);
+ ns = ns_get_default();
+ if (ns)
+ ns->relative_default_ns = ns_id;
default_ns = ns_lookup(ns_get_default_id());
if (!default_ns) {
diff --git a/zebra/zebra_ns.h b/zebra/zebra_ns.h
index dc79a83db0..f7d1f40782 100644
--- a/zebra/zebra_ns.h
+++ b/zebra/zebra_ns.h
@@ -67,9 +67,12 @@ struct zebra_ns *zebra_ns_lookup(ns_id_t ns_id);
int zebra_ns_init(const char *optional_default_name);
int zebra_ns_enable(ns_id_t ns_id, void **info);
int zebra_ns_disabled(struct ns *ns);
-int zebra_ns_early_shutdown(struct ns *ns);
-int zebra_ns_final_shutdown(struct ns *ns);
-
+int zebra_ns_early_shutdown(struct ns *ns,
+ void *param_in __attribute__((unused)),
+ void **param_out __attribute__((unused)));
+int zebra_ns_final_shutdown(struct ns *ns,
+ void *param_in __attribute__((unused)),
+ void **param_out __attribute__((unused)));
int zebra_ns_config_write(struct vty *vty, struct ns *ns);
#ifdef __cplusplus
diff --git a/zebra/zebra_pw.c b/zebra/zebra_pw.c
index c26b7a6157..273843baa2 100644
--- a/zebra/zebra_pw.c
+++ b/zebra/zebra_pw.c
@@ -24,6 +24,8 @@
#include "thread.h"
#include "command.h"
#include "vrf.h"
+#include "lib/json.h"
+#include "printfrr.h"
#include "zebra/debug.h"
#include "zebra/rib.h"
@@ -506,6 +508,155 @@ DEFUN (show_pseudowires,
return CMD_SUCCESS;
}
+static void vty_show_mpls_pseudowire_detail(struct vty *vty)
+{
+ struct zebra_vrf *zvrf;
+ struct zebra_pw *pw;
+ struct route_entry *re;
+ struct nexthop *nexthop;
+
+ zvrf = vrf_info_lookup(VRF_DEFAULT);
+ if (!zvrf)
+ return;
+
+ RB_FOREACH (pw, zebra_pw_head, &zvrf->pseudowires) {
+ char buf_nbr[INET6_ADDRSTRLEN];
+ char buf_nh[100];
+
+ vty_out(vty, "Interface: %s\n", pw->ifname);
+ inet_ntop(pw->af, &pw->nexthop, buf_nbr, sizeof(buf_nbr));
+ vty_out(vty, " Neighbor: %s\n",
+ (pw->af != AF_UNSPEC) ? buf_nbr : "-");
+ if (pw->local_label != MPLS_NO_LABEL)
+ vty_out(vty, " Local Label: %u\n", pw->local_label);
+ else
+ vty_out(vty, " Local Label: %s\n", "-");
+ if (pw->remote_label != MPLS_NO_LABEL)
+ vty_out(vty, " Remote Label: %u\n", pw->remote_label);
+ else
+ vty_out(vty, " Remote Label: %s\n", "-");
+ vty_out(vty, " Protocol: %s\n",
+ zebra_route_string(pw->protocol));
+ if (pw->protocol == ZEBRA_ROUTE_LDP)
+ vty_out(vty, " VC-ID: %u\n", pw->data.ldp.pwid);
+ vty_out(vty, " Status: %s \n",
+ (zebra_pw_enabled(pw) && pw->status == PW_STATUS_UP)
+ ? "Up"
+ : "Down");
+ re = rib_match(family2afi(pw->af), SAFI_UNICAST, pw->vrf_id,
+ &pw->nexthop, NULL);
+ if (re) {
+ for (ALL_NEXTHOPS_PTR(rib_active_nhg(re), nexthop)) {
+ snprintfrr(buf_nh, sizeof(buf_nh), "%pNHv",
+ nexthop);
+ vty_out(vty, " Next Hop: %s\n", buf_nh);
+ if (nexthop->nh_label)
+ vty_out(vty, " Next Hop label: %u\n",
+ nexthop->nh_label->label[0]);
+ else
+ vty_out(vty, " Next Hop label: %s\n",
+ "-");
+ }
+ }
+ }
+}
+
+static void vty_show_mpls_pseudowire(struct zebra_pw *pw, json_object *json_pws)
+{
+ struct route_entry *re;
+ struct nexthop *nexthop;
+ char buf_nbr[INET6_ADDRSTRLEN];
+ char buf_nh[100];
+ json_object *json_pw = NULL;
+ json_object *json_nexthop = NULL;
+ json_object *json_nexthops = NULL;
+
+ json_nexthops = json_object_new_array();
+ json_pw = json_object_new_object();
+
+ json_object_string_add(json_pw, "interface", pw->ifname);
+ if (pw->af == AF_UNSPEC)
+ json_object_string_add(json_pw, "neighbor", "-");
+ else {
+ inet_ntop(pw->af, &pw->nexthop, buf_nbr, sizeof(buf_nbr));
+ json_object_string_add(json_pw, "neighbor", buf_nbr);
+ }
+ if (pw->local_label != MPLS_NO_LABEL)
+ json_object_int_add(json_pw, "localLabel", pw->local_label);
+ else
+ json_object_string_add(json_pw, "localLabel", "-");
+ if (pw->remote_label != MPLS_NO_LABEL)
+ json_object_int_add(json_pw, "remoteLabel", pw->remote_label);
+ else
+ json_object_string_add(json_pw, "remoteLabel", "-");
+ json_object_string_add(json_pw, "protocol",
+ zebra_route_string(pw->protocol));
+ if (pw->protocol == ZEBRA_ROUTE_LDP)
+ json_object_int_add(json_pw, "vcId", pw->data.ldp.pwid);
+ json_object_string_add(
+ json_pw, "Status",
+ (zebra_pw_enabled(pw) && pw->status == PW_STATUS_UP) ? "Up"
+ : "Down");
+ re = rib_match(family2afi(pw->af), SAFI_UNICAST, pw->vrf_id,
+ &pw->nexthop, NULL);
+ if (re) {
+ for (ALL_NEXTHOPS_PTR(rib_active_nhg(re), nexthop)) {
+ json_nexthop = json_object_new_object();
+ snprintfrr(buf_nh, sizeof(buf_nh), "%pNHv", nexthop);
+ json_object_string_add(json_nexthop, "nexthop", buf_nh);
+ if (nexthop->nh_label)
+ json_object_int_add(
+ json_nexthop, "nhLabel",
+ nexthop->nh_label->label[0]);
+ else
+ json_object_string_add(json_nexthop, "nhLabel",
+ "-");
+
+ json_object_array_add(json_nexthops, json_nexthop);
+ }
+ json_object_object_add(json_pw, "nexthops", json_nexthops);
+ }
+ json_object_array_add(json_pws, json_pw);
+}
+
+static void vty_show_mpls_pseudowire_detail_json(struct vty *vty)
+{
+ json_object *json = NULL;
+ json_object *json_pws = NULL;
+ struct zebra_vrf *zvrf;
+ struct zebra_pw *pw;
+
+ zvrf = vrf_info_lookup(VRF_DEFAULT);
+ if (!zvrf)
+ return;
+
+ json = json_object_new_object();
+ json_pws = json_object_new_array();
+ RB_FOREACH (pw, zebra_pw_head, &zvrf->pseudowires) {
+ vty_show_mpls_pseudowire(pw, json_pws);
+ }
+ json_object_object_add(json, "pw", json_pws);
+ vty_out(vty, "%s\n",
+ json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY));
+ json_object_free(json);
+}
+
+DEFUN(show_pseudowires_detail, show_pseudowires_detail_cmd,
+ "show mpls pseudowires detail [json]$json",
+ SHOW_STR MPLS_STR
+ "Pseudowires\n"
+ "Detailed output\n" JSON_STR)
+{
+ bool uj = use_json(argc, argv);
+
+ if (uj)
+ vty_show_mpls_pseudowire_detail_json(vty);
+ else
+ vty_show_mpls_pseudowire_detail(vty);
+
+ return CMD_SUCCESS;
+}
+
/* Pseudowire configuration write function. */
static int zebra_pw_config(struct vty *vty)
{
@@ -568,4 +719,5 @@ void zebra_pw_vty_init(void)
install_element(PW_NODE, &pseudowire_control_word_cmd);
install_element(VIEW_NODE, &show_pseudowires_cmd);
+ install_element(VIEW_NODE, &show_pseudowires_detail_cmd);
}
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index f89656201c..d491982d62 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -125,7 +125,7 @@ _rnode_zlog(const char *_func, vrf_id_t vrf_id, struct route_node *rn,
va_end(ap);
if (rn) {
- rib_table_info_t *info = srcdest_rnode_table_info(rn);
+ struct rib_table_info *info = srcdest_rnode_table_info(rn);
srcdest_rnode2str(rn, buf, sizeof(buf));
if (info->safi == SAFI_MULTICAST)
@@ -211,28 +211,29 @@ static void route_entry_attach_ref(struct route_entry *re,
zebra_nhg_increment_ref(new);
}
-int route_entry_update_nhe(struct route_entry *re, struct nhg_hash_entry *new)
+int route_entry_update_nhe(struct route_entry *re,
+ struct nhg_hash_entry *new_nhghe)
{
struct nhg_hash_entry *old;
int ret = 0;
- if (new == NULL) {
+ if (new_nhghe == NULL) {
if (re->nhe)
zebra_nhg_decrement_ref(re->nhe);
re->nhe = NULL;
goto done;
}
- if ((re->nhe_id != 0) && (re->nhe_id != new->id)) {
+ if ((re->nhe_id != 0) && (re->nhe_id != new_nhghe->id)) {
old = re->nhe;
- route_entry_attach_ref(re, new);
+ route_entry_attach_ref(re, new_nhghe);
if (old)
zebra_nhg_decrement_ref(old);
} else if (!re->nhe)
/* This is the first time it's being attached */
- route_entry_attach_ref(re, new);
+ route_entry_attach_ref(re, new_nhghe);
done:
return ret;
@@ -420,7 +421,7 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re,
struct route_entry *old)
{
struct nexthop *nexthop;
- rib_table_info_t *info = srcdest_rnode_table_info(rn);
+ struct rib_table_info *info = srcdest_rnode_table_info(rn);
struct zebra_vrf *zvrf = vrf_info_lookup(re->vrf_id);
const struct prefix *p, *src_p;
enum zebra_dplane_result ret;
@@ -503,7 +504,7 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re,
void rib_uninstall_kernel(struct route_node *rn, struct route_entry *re)
{
struct nexthop *nexthop;
- rib_table_info_t *info = srcdest_rnode_table_info(rn);
+ struct rib_table_info *info = srcdest_rnode_table_info(rn);
struct zebra_vrf *zvrf = vrf_info_lookup(re->vrf_id);
if (info->safi != SAFI_UNICAST) {
@@ -546,7 +547,7 @@ void rib_uninstall_kernel(struct route_node *rn, struct route_entry *re)
/* Uninstall the route from kernel. */
static void rib_uninstall(struct route_node *rn, struct route_entry *re)
{
- rib_table_info_t *info = srcdest_rnode_table_info(rn);
+ struct rib_table_info *info = srcdest_rnode_table_info(rn);
rib_dest_t *dest = rib_dest_from_rnode(rn);
struct nexthop *nexthop;
@@ -3085,7 +3086,7 @@ int rib_add(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type,
return rib_add_multipath(afi, safi, p, src_p, re, ng);
}
-static const char *rib_update_event2str(rib_update_event_t event)
+static const char *rib_update_event2str(enum rib_update_event event)
{
const char *ret = "UNKNOWN";
@@ -3125,7 +3126,7 @@ static void rib_update_route_node(struct route_node *rn, int type)
}
/* Schedule routes of a particular table (address-family) based on event. */
-void rib_update_table(struct route_table *table, rib_update_event_t event)
+void rib_update_table(struct route_table *table, enum rib_update_event event)
{
struct route_node *rn;
@@ -3133,13 +3134,14 @@ void rib_update_table(struct route_table *table, rib_update_event_t event)
struct zebra_vrf *zvrf;
struct vrf *vrf;
- zvrf = table->info ? ((rib_table_info_t *)table->info)->zvrf
- : NULL;
+ zvrf = table->info
+ ? ((struct rib_table_info *)table->info)->zvrf
+ : NULL;
vrf = zvrf ? zvrf->vrf : NULL;
zlog_debug("%s: %s VRF %s Table %u event %s", __func__,
table->info ? afi2str(
- ((rib_table_info_t *)table->info)->afi)
+ ((struct rib_table_info *)table->info)->afi)
: "Unknown",
VRF_LOGNAME(vrf), zvrf ? zvrf->table_id : 0,
rib_update_event2str(event));
@@ -3173,7 +3175,7 @@ void rib_update_table(struct route_table *table, rib_update_event_t event)
}
}
-static void rib_update_handle_vrf(vrf_id_t vrf_id, rib_update_event_t event)
+static void rib_update_handle_vrf(vrf_id_t vrf_id, enum rib_update_event event)
{
struct route_table *table;
@@ -3191,7 +3193,7 @@ static void rib_update_handle_vrf(vrf_id_t vrf_id, rib_update_event_t event)
rib_update_table(table, event);
}
-static void rib_update_handle_vrf_all(rib_update_event_t event)
+static void rib_update_handle_vrf_all(enum rib_update_event event)
{
struct zebra_router_table *zrt;
@@ -3205,13 +3207,13 @@ static void rib_update_handle_vrf_all(rib_update_event_t event)
}
struct rib_update_ctx {
- rib_update_event_t event;
+ enum rib_update_event event;
bool vrf_all;
vrf_id_t vrf_id;
};
static struct rib_update_ctx *rib_update_ctx_init(vrf_id_t vrf_id,
- rib_update_event_t event)
+ enum rib_update_event event)
{
struct rib_update_ctx *ctx;
@@ -3251,7 +3253,7 @@ static int rib_update_handler(struct thread *thread)
static struct thread *t_rib_update_threads[RIB_UPDATE_MAX];
/* Schedule a RIB update event for specific vrf */
-void rib_update_vrf(vrf_id_t vrf_id, rib_update_event_t event)
+void rib_update_vrf(vrf_id_t vrf_id, enum rib_update_event event)
{
struct rib_update_ctx *ctx;
@@ -3271,7 +3273,7 @@ void rib_update_vrf(vrf_id_t vrf_id, rib_update_event_t event)
}
/* Schedule a RIB update event for all vrfs */
-void rib_update(rib_update_event_t event)
+void rib_update(enum rib_update_event event)
{
struct rib_update_ctx *ctx;
@@ -3425,7 +3427,7 @@ unsigned long rib_score_proto(uint8_t proto, unsigned short instance)
void rib_close_table(struct route_table *table)
{
struct route_node *rn;
- rib_table_info_t *info;
+ struct rib_table_info *info;
rib_dest_t *dest;
if (!table)
diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c
index f9c74c7462..ad2e00b1ec 100644
--- a/zebra/zebra_rnh.c
+++ b/zebra/zebra_rnh.c
@@ -57,8 +57,8 @@ static void free_state(vrf_id_t vrf_id, struct route_entry *re,
static void copy_state(struct rnh *rnh, const struct route_entry *re,
struct route_node *rn);
static int compare_state(struct route_entry *r1, struct route_entry *r2);
-static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type,
- vrf_id_t vrf_id);
+static int send_client(struct rnh *rnh, struct zserv *client,
+ enum rnh_type type, vrf_id_t vrf_id);
static void print_rnh(struct route_node *rn, struct vty *vty);
static int zebra_client_cleanup_rnh(struct zserv *client);
@@ -68,7 +68,7 @@ void zebra_rnh_init(void)
}
static inline struct route_table *get_rnh_table(vrf_id_t vrfid, afi_t afi,
- rnh_type_t type)
+ enum rnh_type type)
{
struct zebra_vrf *zvrf;
struct route_table *t = NULL;
@@ -148,7 +148,7 @@ static void zebra_rnh_store_in_routing_table(struct rnh *rnh)
route_unlock_node(rn);
}
-struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type,
+struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, enum rnh_type type,
bool *exists)
{
struct route_table *table;
@@ -207,7 +207,8 @@ struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type,
return (rn->info);
}
-struct rnh *zebra_lookup_rnh(struct prefix *p, vrf_id_t vrfid, rnh_type_t type)
+struct rnh *zebra_lookup_rnh(struct prefix *p, vrf_id_t vrfid,
+ enum rnh_type type)
{
struct route_table *table;
struct route_node *rn;
@@ -258,7 +259,7 @@ void zebra_free_rnh(struct rnh *rnh)
XFREE(MTYPE_RNH, rnh);
}
-static void zebra_delete_rnh(struct rnh *rnh, rnh_type_t type)
+static void zebra_delete_rnh(struct rnh *rnh, enum rnh_type type)
{
struct route_node *rn;
@@ -289,7 +290,7 @@ static void zebra_delete_rnh(struct rnh *rnh, rnh_type_t type)
* and as such it will have a resolved rnh.
*/
void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client,
- rnh_type_t type, vrf_id_t vrf_id)
+ enum rnh_type type, vrf_id_t vrf_id)
{
if (IS_ZEBRA_DEBUG_NHT) {
char buf[PREFIX2STR_BUFFER];
@@ -308,7 +309,7 @@ void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client,
}
void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client,
- rnh_type_t type)
+ enum rnh_type type)
{
if (IS_ZEBRA_DEBUG_NHT) {
char buf[PREFIX2STR_BUFFER];
@@ -804,7 +805,7 @@ static void zebra_rnh_eval_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi,
/* Evaluate one tracked entry */
static void zebra_rnh_evaluate_entry(struct zebra_vrf *zvrf, afi_t afi,
- int force, rnh_type_t type,
+ int force, enum rnh_type type,
struct route_node *nrn)
{
struct rnh *rnh;
@@ -851,7 +852,7 @@ static void zebra_rnh_evaluate_entry(struct zebra_vrf *zvrf, afi_t afi,
* covers multiple nexthops we are interested in.
*/
static void zebra_rnh_clear_nhc_flag(struct zebra_vrf *zvrf, afi_t afi,
- rnh_type_t type, struct route_node *nrn)
+ enum rnh_type type, struct route_node *nrn)
{
struct rnh *rnh;
struct route_entry *re;
@@ -875,7 +876,7 @@ static void zebra_rnh_clear_nhc_flag(struct zebra_vrf *zvrf, afi_t afi,
* of a particular VRF and address-family or a specific prefix.
*/
void zebra_evaluate_rnh(struct zebra_vrf *zvrf, afi_t afi, int force,
- rnh_type_t type, struct prefix *p)
+ enum rnh_type type, struct prefix *p)
{
struct route_table *rnh_table;
struct route_node *nrn;
@@ -911,7 +912,7 @@ void zebra_evaluate_rnh(struct zebra_vrf *zvrf, afi_t afi, int force,
}
void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, struct vty *vty,
- rnh_type_t type, struct prefix *p)
+ enum rnh_type type, struct prefix *p)
{
struct route_table *table;
struct route_node *rn;
@@ -997,8 +998,8 @@ static int compare_state(struct route_entry *r1, struct route_entry *r2)
return 0;
}
-static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type,
- vrf_id_t vrf_id)
+static int send_client(struct rnh *rnh, struct zserv *client,
+ enum rnh_type type, vrf_id_t vrf_id)
{
struct stream *s;
struct route_entry *re;
@@ -1134,7 +1135,7 @@ static void print_rnh(struct route_node *rn, struct vty *vty)
}
static int zebra_cleanup_rnh_client(vrf_id_t vrf_id, afi_t afi,
- struct zserv *client, rnh_type_t type)
+ struct zserv *client, enum rnh_type type)
{
struct route_table *ntable;
struct route_node *nrn;
diff --git a/zebra/zebra_rnh.h b/zebra/zebra_rnh.h
index 6e2dab8d9f..f07e5bc791 100644
--- a/zebra/zebra_rnh.h
+++ b/zebra/zebra_rnh.h
@@ -31,7 +31,7 @@ extern "C" {
extern void zebra_rnh_init(void);
-static inline const char *rnh_type2str(rnh_type_t type)
+static inline const char *rnh_type2str(enum rnh_type type)
{
switch (type) {
case RNH_NEXTHOP_TYPE:
@@ -44,20 +44,20 @@ static inline const char *rnh_type2str(rnh_type_t type)
}
extern struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid,
- rnh_type_t type, bool *exists);
+ enum rnh_type type, bool *exists);
extern struct rnh *zebra_lookup_rnh(struct prefix *p, vrf_id_t vrfid,
- rnh_type_t type);
+ enum rnh_type type);
extern void zebra_free_rnh(struct rnh *rnh);
extern void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client,
- rnh_type_t type, vrf_id_t vrfid);
+ enum rnh_type type, vrf_id_t vrfid);
extern void zebra_register_rnh_pseudowire(vrf_id_t, struct zebra_pw *);
extern void zebra_deregister_rnh_pseudowire(vrf_id_t, struct zebra_pw *);
extern void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client,
- rnh_type_t type);
+ enum rnh_type type);
extern void zebra_evaluate_rnh(struct zebra_vrf *zvrf, afi_t afi, int force,
- rnh_type_t type, struct prefix *p);
+ enum rnh_type type, struct prefix *p);
extern void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, struct vty *vty,
- rnh_type_t type, struct prefix *p);
+ enum rnh_type type, struct prefix *p);
extern char *rnh_str(struct rnh *rnh, char *buf, int size);
extern int rnh_resolve_via_default(struct zebra_vrf *zvrf, int family);
diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c
index ea2b6752b3..61fef8779f 100644
--- a/zebra/zebra_router.c
+++ b/zebra/zebra_router.c
@@ -66,6 +66,22 @@ zebra_router_table_entry_compare(const struct zebra_router_table *e1,
return (e1->safi - e2->safi);
}
+struct zebra_router_table *zebra_router_find_zrt(struct zebra_vrf *zvrf,
+ uint32_t tableid, afi_t afi,
+ safi_t safi)
+{
+ struct zebra_router_table finder;
+ struct zebra_router_table *zrt;
+
+ memset(&finder, 0, sizeof(finder));
+ finder.afi = afi;
+ finder.safi = safi;
+ finder.tableid = tableid;
+ finder.ns_id = zvrf->zns->ns_id;
+ zrt = RB_FIND(zebra_router_table_head, &zrouter.tables, &finder);
+
+ return zrt;
+}
struct route_table *zebra_router_find_table(struct zebra_vrf *zvrf,
uint32_t tableid, afi_t afi,
@@ -93,7 +109,7 @@ struct route_table *zebra_router_get_table(struct zebra_vrf *zvrf,
{
struct zebra_router_table finder;
struct zebra_router_table *zrt;
- rib_table_info_t *info;
+ struct rib_table_info *info;
memset(&finder, 0, sizeof(finder));
finder.afi = afi;
@@ -133,7 +149,7 @@ void zebra_router_show_table_summary(struct vty *vty)
vty_out(vty,
"---------------------------------------------------------------------------\n");
RB_FOREACH (zrt, zebra_router_table_head, &zrouter.tables) {
- rib_table_info_t *info = route_table_get_info(zrt->table);
+ struct rib_table_info *info = route_table_get_info(zrt->table);
vty_out(vty, "%-16s%5d %9d %7s %15s %8d %10lu\n", info->zvrf->vrf->name,
zrt->ns_id, info->zvrf->vrf->vrf_id,
diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h
index 773e5a6415..863c5fa71c 100644
--- a/zebra/zebra_router.h
+++ b/zebra/zebra_router.h
@@ -186,6 +186,9 @@ extern void zebra_router_init(void);
extern void zebra_router_cleanup(void);
extern void zebra_router_terminate(void);
+extern struct zebra_router_table *zebra_router_find_zrt(struct zebra_vrf *zvrf,
+ uint32_t tableid,
+ afi_t afi, safi_t safi);
extern struct route_table *zebra_router_find_table(struct zebra_vrf *zvrf,
uint32_t tableid, afi_t afi,
safi_t safi);
diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h
index 268ee12a65..d262faa070 100644
--- a/zebra/zebra_vrf.h
+++ b/zebra/zebra_vrf.h
@@ -33,10 +33,10 @@ extern "C" {
#endif
/* MPLS (Segment Routing) global block */
-typedef struct mpls_srgb_t_ {
+struct mpls_srgb {
uint32_t start_label;
uint32_t end_label;
-} mpls_srgb_t;
+};
struct zebra_rmap {
char *name;
@@ -111,7 +111,7 @@ struct zebra_vrf {
struct route_table *fec_table[AFI_MAX];
/* MPLS Segment Routing Global block */
- mpls_srgb_t mpls_srgb;
+ struct mpls_srgb mpls_srgb;
/* Pseudowires. */
struct zebra_pw_head pseudowires;
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 8024db4ca7..9718b40d9d 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -357,7 +357,8 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn,
const char *mcast_info = "";
if (mcast) {
- rib_table_info_t *info = srcdest_rnode_table_info(rn);
+ struct rib_table_info *info =
+ srcdest_rnode_table_info(rn);
mcast_info = (info->safi == SAFI_MULTICAST)
? " using Multicast RIB"
: " using Unicast RIB";
@@ -978,7 +979,7 @@ static void do_show_ip_route_all(struct vty *vty, struct zebra_vrf *zvrf,
unsigned short ospf_instance_id)
{
struct zebra_router_table *zrt;
- rib_table_info_t *info;
+ struct rib_table_info *info;
RB_FOREACH (zrt, zebra_router_table_head,
&zrouter.tables) {
@@ -1059,7 +1060,7 @@ DEFPY (show_ip_nht,
afi_t afi = ipv4 ? AFI_IP : AFI_IP6;
vrf_id_t vrf_id = VRF_DEFAULT;
struct prefix prefix, *p = NULL;
- rnh_type_t rtype;
+ enum rnh_type rtype;
if (strcmp(type, "nht") == 0)
rtype = RNH_NEXTHOP_TYPE;
@@ -1349,8 +1350,9 @@ DEFPY (show_nexthop_group,
else if (v6)
afi = AFI_IP6;
- if (vrf_is_backend_netns() && (vrf_name || vrf_all)) {
- vty_out(vty, "VRF subcommand does not make any sense in l3mdev based vrf's");
+ if (!vrf_is_backend_netns() && (vrf_name || vrf_all)) {
+ vty_out(vty,
+ "VRF subcommand does not make any sense in l3mdev based vrf's\n");
return CMD_WARNING;
}
@@ -1832,8 +1834,8 @@ static void vty_show_ip_route_summary(struct vty *vty,
if (!use_json)
vty_out(vty, "%-20s %-20s %s (vrf %s)\n", "Route Source",
"Routes", "FIB",
- zvrf_name(((rib_table_info_t *)route_table_get_info(
- table))
+ zvrf_name(((struct rib_table_info *)
+ route_table_get_info(table))
->zvrf));
for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
@@ -1980,8 +1982,8 @@ static void vty_show_ip_route_summary_prefix(struct vty *vty,
if (!use_json)
vty_out(vty, "%-20s %-20s %s (vrf %s)\n", "Route Source",
"Prefix Routes", "FIB",
- zvrf_name(((rib_table_info_t *)route_table_get_info(
- table))
+ zvrf_name(((struct rib_table_info *)
+ route_table_get_info(table))
->zvrf));
for (i = 0; i < ZEBRA_ROUTE_MAX; i++) {
diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c
index d85f48e570..998c035656 100644
--- a/zebra/zebra_vxlan.c
+++ b/zebra/zebra_vxlan.c
@@ -1194,7 +1194,7 @@ static void zvni_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json)
ifindex_t ifindex;
ifindex = mac->fwd_info.local.ifindex;
- zns = zebra_ns_lookup(NS_DEFAULT);
+ zns = zebra_ns_lookup(mac->fwd_info.local.ns_id);
ifp = if_lookup_by_index_per_ns(zns, ifindex);
if (!ifp)
return;
@@ -1276,7 +1276,7 @@ static void zvni_print_mac(zebra_mac_t *mac, void *ctxt, json_object *json)
ifindex_t ifindex;
ifindex = mac->fwd_info.local.ifindex;
- zns = zebra_ns_lookup(NS_DEFAULT);
+ zns = zebra_ns_lookup(mac->fwd_info.local.ns_id);
ifp = if_lookup_by_index_per_ns(zns, ifindex);
if (!ifp)
return;
@@ -1368,7 +1368,7 @@ static void zvni_print_mac_hash(struct hash_bucket *bucket, void *ctxt)
if (wctx->flags & SHOW_REMOTE_MAC_FROM_VTEP)
return;
- zns = zebra_ns_lookup(NS_DEFAULT);
+ zns = zebra_ns_lookup(mac->fwd_info.local.ns_id);
ifindex = mac->fwd_info.local.ifindex;
ifp = if_lookup_by_index_per_ns(zns, ifindex);
if (!ifp) // unexpected
@@ -2731,7 +2731,12 @@ static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni,
zebra_mac_t *mac = NULL;
struct zebra_if *zif = NULL;
struct zebra_l2info_vxlan *vxl = NULL;
+ struct zebra_vrf *zvrf;
+ ns_id_t local_ns_id = NS_DEFAULT;
+ zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id);
+ if (zvrf && zvrf->zns)
+ local_ns_id = zvrf->zns->ns_id;
zif = zvni->vxlan_if->info;
if (!zif)
return -1;
@@ -2756,6 +2761,7 @@ static int zvni_gw_macip_add(struct interface *ifp, zebra_vni_t *zvni,
SET_FLAG(mac->flags, ZEBRA_MAC_DEF_GW);
memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
mac->fwd_info.local.ifindex = ifp->ifindex;
+ mac->fwd_info.local.ns_id = local_ns_id;
mac->fwd_info.local.vid = vxl->access_vlan;
n = zvni_neigh_lookup(zvni, ip);
@@ -3522,6 +3528,68 @@ static int zvni_mac_send_del_to_client(vni_t vni, struct ethaddr *macaddr)
0 /* seq */, ZEBRA_NEIGH_ACTIVE, ZEBRA_MACIP_DEL);
}
+struct zvni_from_svi_param {
+ struct interface *br_if;
+ struct interface *svi_if;
+ struct zebra_if *zif;
+ uint8_t bridge_vlan_aware;
+ vlanid_t vid;
+};
+
+static int zvni_map_vlan_ns(struct ns *ns,
+ void *_in_param,
+ void **_p_zvni)
+{
+ struct zebra_ns *zns = ns->info;
+ struct route_node *rn;
+ struct interface *br_if;
+ zebra_vni_t **p_zvni = (zebra_vni_t **)_p_zvni;
+ zebra_vni_t *zvni;
+ struct interface *tmp_if = NULL;
+ struct zebra_if *zif;
+ struct zebra_l2info_vxlan *vxl = NULL;
+ struct zvni_from_svi_param *in_param =
+ (struct zvni_from_svi_param *)_in_param;
+ int found = 0;
+
+ if (!in_param)
+ return NS_WALK_STOP;
+ br_if = in_param->br_if;
+ zif = in_param->zif;
+ assert(zif);
+ assert(br_if);
+
+ /* See if this interface (or interface plus VLAN Id) maps to a VxLAN */
+ /* TODO: Optimize with a hash. */
+ for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
+ tmp_if = (struct interface *)rn->info;
+ if (!tmp_if)
+ continue;
+ zif = tmp_if->info;
+ if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
+ continue;
+ if (!if_is_operative(tmp_if))
+ continue;
+ vxl = &zif->l2info.vxl;
+
+ if (zif->brslave_info.br_if != br_if)
+ continue;
+
+ if (!in_param->bridge_vlan_aware
+ || vxl->access_vlan == in_param->vid) {
+ found = 1;
+ break;
+ }
+ }
+ if (!found)
+ return NS_WALK_CONTINUE;
+
+ zvni = zvni_lookup(vxl->vni);
+ if (p_zvni)
+ *p_zvni = zvni;
+ return NS_WALK_STOP;
+}
+
/*
* Map port or (port, VLAN) to a VNI. This is invoked upon getting MAC
* notifications, to see if they are of interest.
@@ -3529,25 +3597,51 @@ static int zvni_mac_send_del_to_client(vni_t vni, struct ethaddr *macaddr)
static zebra_vni_t *zvni_map_vlan(struct interface *ifp,
struct interface *br_if, vlanid_t vid)
{
- struct zebra_ns *zns;
- struct route_node *rn;
- struct interface *tmp_if = NULL;
struct zebra_if *zif;
struct zebra_l2info_bridge *br;
- struct zebra_l2info_vxlan *vxl = NULL;
- uint8_t bridge_vlan_aware;
- zebra_vni_t *zvni;
- int found = 0;
+ zebra_vni_t **p_zvni;
+ zebra_vni_t *zvni = NULL;
+ struct zvni_from_svi_param in_param;
/* Determine if bridge is VLAN-aware or not */
zif = br_if->info;
assert(zif);
br = &zif->l2info.br;
- bridge_vlan_aware = br->vlan_aware;
+ in_param.bridge_vlan_aware = br->vlan_aware;
+ in_param.vid = vid;
+ in_param.br_if = br_if;
+ in_param.zif = zif;
+ p_zvni = &zvni;
+
+ ns_walk_func(zvni_map_vlan_ns,
+ (void *)&in_param,
+ (void **)p_zvni);
+ return zvni;
+}
+
+static int zvni_from_svi_ns(struct ns *ns,
+ void *_in_param,
+ void **_p_zvni)
+{
+ struct zebra_ns *zns = ns->info;
+ struct route_node *rn;
+ struct interface *br_if;
+ zebra_vni_t **p_zvni = (zebra_vni_t **)_p_zvni;
+ zebra_vni_t *zvni;
+ struct interface *tmp_if = NULL;
+ struct zebra_if *zif;
+ struct zebra_l2info_vxlan *vxl = NULL;
+ struct zvni_from_svi_param *in_param =
+ (struct zvni_from_svi_param *)_in_param;
+ int found = 0;
+
+ if (!in_param)
+ return NS_WALK_STOP;
+ br_if = in_param->br_if;
+ zif = in_param->zif;
+ assert(zif);
- /* See if this interface (or interface plus VLAN Id) maps to a VxLAN */
/* TODO: Optimize with a hash. */
- zns = zebra_ns_lookup(NS_DEFAULT);
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
tmp_if = (struct interface *)rn->info;
if (!tmp_if)
@@ -3562,17 +3656,20 @@ static zebra_vni_t *zvni_map_vlan(struct interface *ifp,
if (zif->brslave_info.br_if != br_if)
continue;
- if (!bridge_vlan_aware || vxl->access_vlan == vid) {
+ if (!in_param->bridge_vlan_aware
+ || vxl->access_vlan == !in_param->vid) {
found = 1;
break;
}
}
if (!found)
- return NULL;
+ return NS_WALK_CONTINUE;
zvni = zvni_lookup(vxl->vni);
- return zvni;
+ if (p_zvni)
+ *p_zvni = zvni;
+ return NS_WALK_STOP;
}
/*
@@ -3582,16 +3679,11 @@ static zebra_vni_t *zvni_map_vlan(struct interface *ifp,
static zebra_vni_t *zvni_from_svi(struct interface *ifp,
struct interface *br_if)
{
- struct zebra_ns *zns;
- struct route_node *rn;
- struct interface *tmp_if = NULL;
- struct zebra_if *zif;
struct zebra_l2info_bridge *br;
- struct zebra_l2info_vxlan *vxl = NULL;
- uint8_t bridge_vlan_aware;
- vlanid_t vid = 0;
- zebra_vni_t *zvni;
- int found = 0;
+ zebra_vni_t *zvni = NULL;
+ zebra_vni_t **p_zvni;
+ struct zebra_if *zif;
+ struct zvni_from_svi_param in_param;
if (!br_if)
return NULL;
@@ -3604,8 +3696,10 @@ static zebra_vni_t *zvni_from_svi(struct interface *ifp,
zif = br_if->info;
assert(zif);
br = &zif->l2info.br;
- bridge_vlan_aware = br->vlan_aware;
- if (bridge_vlan_aware) {
+ in_param.bridge_vlan_aware = br->vlan_aware;
+ in_param.vid = 0;
+
+ if (in_param.bridge_vlan_aware) {
struct zebra_l2info_vlan *vl;
if (!IS_ZEBRA_IF_VLAN(ifp))
@@ -3614,37 +3708,54 @@ static zebra_vni_t *zvni_from_svi(struct interface *ifp,
zif = ifp->info;
assert(zif);
vl = &zif->l2info.vl;
- vid = vl->vid;
+ in_param.vid = vl->vid;
}
+ in_param.br_if = br_if;
+ in_param.zif = zif;
+ p_zvni = &zvni;
/* See if this interface (or interface plus VLAN Id) maps to a VxLAN */
+ ns_walk_func(zvni_from_svi_ns,
+ (void *)&in_param,
+ (void **)p_zvni);
+ return zvni;
+}
+
+static int zvni_map_to_svi_ns(struct ns *ns,
+ void *_in_param,
+ void **_p_ifp)
+{
+ struct zebra_ns *zns = ns->info;
+ struct route_node *rn;
+ struct zvni_from_svi_param *in_param =
+ (struct zvni_from_svi_param *)_in_param;
+ struct zebra_l2info_vlan *vl;
+ struct interface *tmp_if = NULL;
+ struct interface **p_ifp = (struct interface **)_p_ifp;
+ struct zebra_if *zif;
+
+ if (!in_param)
+ return NS_WALK_STOP;
+
/* TODO: Optimize with a hash. */
- zns = zebra_ns_lookup(NS_DEFAULT);
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
tmp_if = (struct interface *)rn->info;
- if (!tmp_if)
+ /* Check oper status of the SVI. */
+ if (!tmp_if || !if_is_operative(tmp_if))
continue;
zif = tmp_if->info;
- if (!zif || zif->zif_type != ZEBRA_IF_VXLAN)
- continue;
- if (!if_is_operative(tmp_if))
- continue;
- vxl = &zif->l2info.vxl;
-
- if (zif->brslave_info.br_if != br_if)
+ if (!zif || zif->zif_type != ZEBRA_IF_VLAN
+ || zif->link != in_param->br_if)
continue;
+ vl = (struct zebra_l2info_vlan *)&zif->l2info.vl;
- if (!bridge_vlan_aware || vxl->access_vlan == vid) {
- found = 1;
- break;
+ if (vl->vid == in_param->vid) {
+ if (p_ifp)
+ *p_ifp = tmp_if;
+ return NS_WALK_STOP;
}
}
-
- if (!found)
- return NULL;
-
- zvni = zvni_lookup(vxl->vni);
- return zvni;
+ return NS_WALK_CONTINUE;
}
/* Map to SVI on bridge corresponding to specified VLAN. This can be one
@@ -3656,15 +3767,11 @@ static zebra_vni_t *zvni_from_svi(struct interface *ifp,
*/
static struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if)
{
- struct zebra_ns *zns;
- struct route_node *rn;
struct interface *tmp_if = NULL;
struct zebra_if *zif;
struct zebra_l2info_bridge *br;
- struct zebra_l2info_vlan *vl;
- uint8_t bridge_vlan_aware;
- int found = 0;
-
+ struct zvni_from_svi_param in_param;
+ struct interface **p_ifp;
/* Defensive check, caller expected to invoke only with valid bridge. */
if (!br_if)
return NULL;
@@ -3673,33 +3780,56 @@ static struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if)
zif = br_if->info;
assert(zif);
br = &zif->l2info.br;
- bridge_vlan_aware = br->vlan_aware;
-
+ in_param.bridge_vlan_aware = br->vlan_aware;
/* Check oper status of the SVI. */
- if (!bridge_vlan_aware)
+ if (!in_param.bridge_vlan_aware)
return if_is_operative(br_if) ? br_if : NULL;
+ in_param.vid = vid;
+ in_param.br_if = br_if;
+ in_param.zif = NULL;
+ p_ifp = &tmp_if;
+ /* Identify corresponding VLAN interface. */
+ ns_walk_func(zvni_map_to_svi_ns,
+ (void *)&in_param,
+ (void **)p_ifp);
+ return tmp_if;
+}
+
+static int zvni_map_to_macvlan_ns(struct ns *ns,
+ void *_in_param,
+ void **_p_ifp)
+{
+ struct zebra_ns *zns = ns->info;
+ struct zvni_from_svi_param *in_param =
+ (struct zvni_from_svi_param *)_in_param;
+ struct interface **p_ifp = (struct interface **)_p_ifp;
+ struct route_node *rn;
+ struct interface *tmp_if = NULL;
+ struct zebra_if *zif;
+
+ if (!in_param)
+ return NS_WALK_STOP;
+
/* Identify corresponding VLAN interface. */
- /* TODO: Optimize with a hash. */
- zns = zebra_ns_lookup(NS_DEFAULT);
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
tmp_if = (struct interface *)rn->info;
/* Check oper status of the SVI. */
if (!tmp_if || !if_is_operative(tmp_if))
continue;
zif = tmp_if->info;
- if (!zif || zif->zif_type != ZEBRA_IF_VLAN
- || zif->link != br_if)
+
+ if (!zif || zif->zif_type != ZEBRA_IF_MACVLAN)
continue;
- vl = &zif->l2info.vl;
- if (vl->vid == vid) {
- found = 1;
- break;
+ if (zif->link == in_param->svi_if) {
+ if (p_ifp)
+ *p_ifp = tmp_if;
+ return NS_WALK_STOP;
}
}
- return found ? tmp_if : NULL;
+ return NS_WALK_CONTINUE;
}
/* Map to MAC-VLAN interface corresponding to specified SVI interface.
@@ -3707,11 +3837,10 @@ static struct interface *zvni_map_to_svi(vlanid_t vid, struct interface *br_if)
static struct interface *zvni_map_to_macvlan(struct interface *br_if,
struct interface *svi_if)
{
- struct zebra_ns *zns;
- struct route_node *rn;
struct interface *tmp_if = NULL;
struct zebra_if *zif;
- int found = 0;
+ struct interface **p_ifp;
+ struct zvni_from_svi_param in_param;
/* Defensive check, caller expected to invoke only with valid bridge. */
if (!br_if)
@@ -3726,28 +3855,19 @@ static struct interface *zvni_map_to_macvlan(struct interface *br_if,
zif = br_if->info;
assert(zif);
- /* Identify corresponding VLAN interface. */
- zns = zebra_ns_lookup(NS_DEFAULT);
- for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
- tmp_if = (struct interface *)rn->info;
- /* Check oper status of the SVI. */
- if (!tmp_if || !if_is_operative(tmp_if))
- continue;
- zif = tmp_if->info;
-
- if (!zif || zif->zif_type != ZEBRA_IF_MACVLAN)
- continue;
-
- if (zif->link == svi_if) {
- found = 1;
- break;
- }
- }
+ in_param.vid = 0;
+ in_param.br_if = br_if;
+ in_param.zif = NULL;
+ in_param.svi_if = svi_if;
+ p_ifp = &tmp_if;
- return found ? tmp_if : NULL;
+ /* Identify corresponding VLAN interface. */
+ ns_walk_func(zvni_map_to_macvlan_ns,
+ (void *)&in_param,
+ (void **)p_ifp);
+ return tmp_if;
}
-
/*
* Install remote MAC into the forwarding plane.
*/
@@ -3900,6 +4020,7 @@ static void zvni_deref_ip2mac(zebra_vni_t *zvni, zebra_mac_t *mac)
static void zvni_read_mac_neigh(zebra_vni_t *zvni, struct interface *ifp)
{
struct zebra_ns *zns;
+ struct zebra_vrf *zvrf;
struct zebra_if *zif;
struct interface *vlan_if;
struct zebra_l2info_vxlan *vxl;
@@ -3907,7 +4028,10 @@ static void zvni_read_mac_neigh(zebra_vni_t *zvni, struct interface *ifp)
zif = ifp->info;
vxl = &zif->l2info.vxl;
- zns = zebra_ns_lookup(NS_DEFAULT);
+ zvrf = zebra_vrf_lookup_by_id(zvni->vrf_id);
+ if (!zvrf || !zvrf->zns)
+ return;
+ zns = zvrf->zns;
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
@@ -4115,18 +4239,21 @@ static int zvni_send_del_to_client(vni_t vni)
return zserv_send_message(client, s);
}
-/*
- * Build the VNI hash table by going over the VxLAN interfaces. This
- * is called when EVPN (advertise-all-vni) is enabled.
- */
-static void zvni_build_hash_table(void)
+static int zvni_build_hash_table_ns(struct ns *ns,
+ void *param_in __attribute__((unused)),
+ void **param_out __attribute__((unused)))
{
- struct zebra_ns *zns;
+ struct zebra_ns *zns = ns->info;
struct route_node *rn;
struct interface *ifp;
+ struct zebra_vrf *zvrf;
+
+ zvrf = zebra_vrf_get_evpn();
+
+ if (!zvrf)
+ return NS_WALK_STOP;
/* Walk VxLAN interfaces and create VNI hash. */
- zns = zebra_ns_lookup(NS_DEFAULT);
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
vni_t vni;
zebra_vni_t *zvni = NULL;
@@ -4143,7 +4270,15 @@ static void zvni_build_hash_table(void)
vxl = &zif->l2info.vxl;
vni = vxl->vni;
-
+ /* link of VXLAN interface should be in zebra_evpn_vrf */
+ if (zvrf->zns->ns_id != vxl->link_nsid) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "Intf %s(%u) VNI %u, link not in same "
+ "namespace than BGP EVPN core instance ",
+ ifp->name, ifp->ifindex, vni);
+ continue;
+ }
/* L3-VNI and L2-VNI are handled seperately */
zl3vni = zl3vni_lookup(vni);
if (zl3vni) {
@@ -4212,7 +4347,7 @@ static void zvni_build_hash_table(void)
zlog_debug(
"Failed to add VNI hash, IF %s(%u) L2-VNI %u",
ifp->name, ifp->ifindex, vni);
- return;
+ return NS_WALK_CONTINUE;
}
if (zvni->local_vtep_ip.s_addr !=
@@ -4249,6 +4384,19 @@ static void zvni_build_hash_table(void)
}
}
}
+ return NS_WALK_CONTINUE;
+}
+
+/*
+ * Build the VNI hash table by going over the VxLAN interfaces. This
+ * is called when EVPN (advertise-all-vni) is enabled.
+ */
+
+static void zvni_build_hash_table(void)
+{
+ ns_walk_func(zvni_build_hash_table_ns,
+ (void *)NULL,
+ (void **)NULL);
}
/*
@@ -5033,14 +5181,22 @@ static int zl3vni_del(zebra_l3vni_t *zl3vni)
return 0;
}
-struct interface *zl3vni_map_to_vxlan_if(zebra_l3vni_t *zl3vni)
+static int zl3vni_map_to_vxlan_if_ns(struct ns *ns,
+ void *_zl3vni,
+ void **_pifp)
{
- struct zebra_ns *zns = NULL;
+ struct zebra_ns *zns = ns->info;
+ zebra_l3vni_t *zl3vni = (zebra_l3vni_t *)_zl3vni;
struct route_node *rn = NULL;
struct interface *ifp = NULL;
+ struct zebra_vrf *zvrf;
+
+ zvrf = zebra_vrf_get_evpn();
+
+ if (!zvrf)
+ return NS_WALK_STOP;
/* loop through all vxlan-interface */
- zns = zebra_ns_lookup(NS_DEFAULT);
for (rn = route_top(zns->if_table); rn; rn = route_next(rn)) {
struct zebra_if *zif = NULL;
@@ -5055,13 +5211,39 @@ struct interface *zl3vni_map_to_vxlan_if(zebra_l3vni_t *zl3vni)
continue;
vxl = &zif->l2info.vxl;
- if (vxl->vni == zl3vni->vni) {
- zl3vni->local_vtep_ip = vxl->vtep_ip;
- return ifp;
+ if (vxl->vni != zl3vni->vni)
+ continue;
+
+ /* link of VXLAN interface should be in zebra_evpn_vrf */
+ if (zvrf->zns->ns_id != vxl->link_nsid) {
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "Intf %s(%u) VNI %u, link not in same "
+ "namespace than BGP EVPN core instance ",
+ ifp->name, ifp->ifindex, vxl->vni);
+ continue;
}
+
+
+ zl3vni->local_vtep_ip = vxl->vtep_ip;
+ if (_pifp)
+ *_pifp = (void *)ifp;
+ return NS_WALK_STOP;
}
- return NULL;
+ return NS_WALK_CONTINUE;
+}
+
+struct interface *zl3vni_map_to_vxlan_if(zebra_l3vni_t *zl3vni)
+{
+ struct interface **p_ifp;
+ struct interface *ifp = NULL;
+
+ p_ifp = &ifp;
+
+ ns_walk_func(zl3vni_map_to_vxlan_if_ns,
+ (void *)zl3vni, (void **)p_ifp);
+ return ifp;
}
struct interface *zl3vni_map_to_svi_if(zebra_l3vni_t *zl3vni)
@@ -5537,7 +5719,7 @@ static void process_remote_macip_add(vni_t vni,
return;
}
- zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
+ zvrf = zebra_vrf_get_evpn();
if (!zvrf)
return;
@@ -8018,6 +8200,11 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
bool upd_neigh = false;
bool is_dup_detect = false;
struct in_addr vtep_ip = {.s_addr = 0};
+ ns_id_t local_ns_id = NS_DEFAULT;
+
+ zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id);
+ if (zvrf && zvrf->zns)
+ local_ns_id = zvrf->zns->ns_id;
/* We are interested in MACs only on ports or (port, VLAN) that
* map to a VNI.
@@ -8041,11 +8228,10 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
return -1;
}
- zvrf = vrf_info_lookup(zvni->vxlan_if->vrf_id);
+ zvrf = zebra_vrf_get_evpn();
if (!zvrf) {
if (IS_ZEBRA_DEBUG_VXLAN)
- zlog_debug(" No Vrf found for vrf_id: %d",
- zvni->vxlan_if->vrf_id);
+ zlog_debug(" No Evpn Global Vrf found");
return -1;
}
@@ -8070,6 +8256,7 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
}
SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
mac->fwd_info.local.ifindex = ifp->ifindex;
+ mac->fwd_info.local.ns_id = local_ns_id;
mac->fwd_info.local.vid = vid;
if (sticky)
SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
@@ -8094,6 +8281,7 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
*/
if (mac_sticky == sticky
&& mac->fwd_info.local.ifindex == ifp->ifindex
+ && mac->fwd_info.local.ns_id == local_ns_id
&& mac->fwd_info.local.vid == vid) {
if (IS_ZEBRA_DEBUG_VXLAN)
zlog_debug(
@@ -8118,6 +8306,7 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
mac->fwd_info.local.ifindex = ifp->ifindex;
+ mac->fwd_info.local.ns_id = local_ns_id;
mac->fwd_info.local.vid = vid;
} else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE) ||
@@ -8155,6 +8344,7 @@ int zebra_vxlan_local_mac_add_update(struct interface *ifp,
SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL);
memset(&mac->fwd_info, 0, sizeof(mac->fwd_info));
mac->fwd_info.local.ifindex = ifp->ifindex;
+ mac->fwd_info.local.ns_id = local_ns_id;
mac->fwd_info.local.vid = vid;
if (sticky)
SET_FLAG(mac->flags, ZEBRA_MAC_STICKY);
@@ -9620,6 +9810,25 @@ stream_failure:
return;
}
+static int macfdb_read_ns(struct ns *ns,
+ void *_in_param __attribute__((unused)),
+ void **out_param __attribute__((unused)))
+{
+ struct zebra_ns *zns = ns->info;
+
+ macfdb_read(zns);
+ return NS_WALK_CONTINUE;
+}
+
+static int neigh_read_ns(struct ns *ns,
+ void *_in_param __attribute__((unused)),
+ void **out_param __attribute__((unused)))
+{
+ struct zebra_ns *zns = ns->info;
+
+ neigh_read(zns);
+ return NS_WALK_CONTINUE;
+}
/*
* Handle message from client to learn (or stop learning) about VNIs and MACs.
@@ -9669,10 +9878,10 @@ void zebra_vxlan_advertise_all_vni(ZAPI_HANDLER_ARGS)
NULL);
/* Read the MAC FDB */
- macfdb_read(zvrf->zns);
+ ns_walk_func(macfdb_read_ns, NULL, NULL);
/* Read neighbors */
- neigh_read(zvrf->zns);
+ ns_walk_func(neigh_read_ns, NULL, NULL);
} else {
/* Cleanup VTEPs for all VNIs - uninstall from
* kernel and free entries.
diff --git a/zebra/zebra_vxlan_private.h b/zebra/zebra_vxlan_private.h
index 0a46fb2075..d2b02df2ad 100644
--- a/zebra/zebra_vxlan_private.h
+++ b/zebra/zebra_vxlan_private.h
@@ -310,6 +310,7 @@ struct zebra_mac_t_ {
union {
struct {
ifindex_t ifindex;
+ ns_id_t ns_id;
vlanid_t vid;
} local;
diff --git a/zebra/zserv.h b/zebra/zserv.h
index 5506c4299d..9d442899f1 100644
--- a/zebra/zserv.h
+++ b/zebra/zserv.h
@@ -72,7 +72,7 @@ struct client_gr_info {
enum zserv_client_capabilities capabilities;
/* GR commands */
- bool delete;
+ bool do_delete;
bool gr_enable;
bool stale_client;