summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/conflicts.yml21
-rw-r--r--Makefile.am4
-rw-r--r--alpine/APKBUILD.in9
-rw-r--r--babeld/babel_zebra.c2
-rw-r--r--babeld/subdir.am5
-rw-r--r--bfdd/bfdd_cli.c2
-rw-r--r--bfdd/bfdd_vty.c4
-rw-r--r--bfdd/subdir.am2
-rw-r--r--bgpd/bgp_attr.c191
-rw-r--r--bgpd/bgp_attr.h40
-rw-r--r--bgpd/bgp_bmp.c7
-rw-r--r--bgpd/bgp_community.h27
-rw-r--r--bgpd/bgp_conditional_adv.c19
-rw-r--r--bgpd/bgp_debug.c52
-rw-r--r--bgpd/bgp_debug.h3
-rw-r--r--bgpd/bgp_dump.c2
-rw-r--r--bgpd/bgp_errors.c6
-rw-r--r--bgpd/bgp_errors.h1
-rw-r--r--bgpd/bgp_evpn.c529
-rw-r--r--bgpd/bgp_evpn_private.h22
-rw-r--r--bgpd/bgp_evpn_vty.c444
-rw-r--r--bgpd/bgp_fsm.c86
-rw-r--r--bgpd/bgp_fsm.h2
-rw-r--r--bgpd/bgp_io.c173
-rw-r--r--bgpd/bgp_labelpool.c2
-rw-r--r--bgpd/bgp_mac.c21
-rw-r--r--bgpd/bgp_memory.c4
-rw-r--r--bgpd/bgp_memory.h2
-rw-r--r--bgpd/bgp_mplsvpn.c528
-rw-r--r--bgpd/bgp_mplsvpn.h46
-rw-r--r--bgpd/bgp_network.c26
-rw-r--r--bgpd/bgp_nht.c15
-rw-r--r--bgpd/bgp_open.c13
-rw-r--r--bgpd/bgp_open.h1
-rw-r--r--bgpd/bgp_orr.c1176
-rw-r--r--bgpd/bgp_orr.h102
-rw-r--r--bgpd/bgp_packet.c68
-rw-r--r--bgpd/bgp_pbr.c3
-rw-r--r--bgpd/bgp_regex.h15
-rw-r--r--bgpd/bgp_route.c338
-rw-r--r--bgpd/bgp_route.h34
-rw-r--r--bgpd/bgp_routemap.c108
-rw-r--r--bgpd/bgp_routemap_nb.c7
-rw-r--r--bgpd/bgp_routemap_nb.h4
-rw-r--r--bgpd/bgp_routemap_nb_config.c52
-rw-r--r--bgpd/bgp_rpki.c125
-rw-r--r--bgpd/bgp_table.h2
-rw-r--r--bgpd/bgp_updgrp.c5
-rw-r--r--bgpd/bgp_updgrp_adv.c5
-rw-r--r--bgpd/bgp_updgrp_packet.c7
-rw-r--r--bgpd/bgp_vty.c478
-rw-r--r--bgpd/bgp_zebra.c80
-rw-r--r--bgpd/bgpd.c82
-rw-r--r--bgpd/bgpd.h163
-rw-r--r--bgpd/rfapi/rfapi.c9
-rw-r--r--bgpd/subdir.am29
-rw-r--r--configure.ac14
-rw-r--r--debian/frr.install1
-rw-r--r--debian/frr.pam1
-rw-r--r--doc/developer/cli.rst2
-rw-r--r--doc/developer/conf.py8
-rw-r--r--doc/developer/vtysh.rst19
-rw-r--r--doc/manpages/conf.py8
-rw-r--r--doc/user/bgp.rst405
-rw-r--r--doc/user/conf.py8
-rw-r--r--doc/user/index.rst1
-rw-r--r--doc/user/installation.rst7
-rw-r--r--doc/user/isisd.rst4
-rw-r--r--doc/user/nexthop_groups.rst29
-rw-r--r--doc/user/ospfd.rst55
-rw-r--r--doc/user/pathd.rst8
-rw-r--r--doc/user/pbr.rst35
-rw-r--r--doc/user/pim.rst2
-rw-r--r--doc/user/pimv6.rst28
-rw-r--r--doc/user/routemap.rst5
-rw-r--r--doc/user/sharp.rst5
-rw-r--r--doc/user/subdir.am1
-rw-r--r--doc/user/zebra.rst57
-rw-r--r--docker/alpine/Dockerfile6
-rw-r--r--eigrpd/eigrp_cli.c2
-rw-r--r--eigrpd/eigrp_dump.c1
-rw-r--r--eigrpd/eigrp_vty.c2
-rw-r--r--eigrpd/subdir.am6
-rw-r--r--grpc/subdir.am7
-rw-r--r--include/linux/rtnetlink.h3
-rw-r--r--include/linux/seg6_local.h32
-rw-r--r--isisd/isis_adjacency.c40
-rw-r--r--isisd/isis_adjacency.h1
-rw-r--r--isisd/isis_circuit.c39
-rw-r--r--isisd/isis_circuit.h5
-rw-r--r--isisd/isis_cli.c43
-rw-r--r--isisd/isis_lfa.c18
-rw-r--r--isisd/isis_lsp.c31
-rw-r--r--isisd/isis_lsp.h1
-rw-r--r--isisd/isis_nb.c13
-rw-r--r--isisd/isis_nb.h6
-rw-r--r--isisd/isis_nb_config.c24
-rw-r--r--isisd/isis_route.c92
-rw-r--r--isisd/isis_route.h5
-rw-r--r--isisd/isis_spf.c27
-rw-r--r--isisd/isis_spf.h4
-rw-r--r--isisd/isis_sr.c5
-rw-r--r--isisd/isis_te.c103
-rw-r--r--isisd/isisd.c138
-rw-r--r--isisd/isisd.h13
-rw-r--r--isisd/subdir.am22
-rw-r--r--ldpd/ldp_vty_cmds.c10
-rw-r--r--ldpd/neighbor.c3
-rw-r--r--ldpd/subdir.am1
-rw-r--r--lib/agentx.c2
-rw-r--r--lib/command.c26
-rw-r--r--lib/command.h100
-rw-r--r--lib/command_graph.c5
-rw-r--r--lib/command_graph.h9
-rw-r--r--lib/command_match.c3
-rw-r--r--lib/command_py.c10
-rw-r--r--lib/filter_cli.c2
-rw-r--r--lib/frrscript.c28
-rw-r--r--lib/frrscript.h5
-rw-r--r--lib/frrstr.c9
-rw-r--r--lib/frrstr.h9
-rw-r--r--lib/grammar_sandbox.c3
-rw-r--r--lib/if.c28
-rw-r--r--lib/if.h8
-rw-r--r--lib/ipaddr.h2
-rw-r--r--lib/libfrr.c4
-rw-r--r--lib/linklist.c5
-rw-r--r--lib/log_vty.c6
-rw-r--r--lib/nexthop_group.c61
-rw-r--r--lib/nexthop_group.h17
-rw-r--r--lib/northbound_cli.c2
-rw-r--r--lib/orr_msg.h94
-rw-r--r--lib/plist.c2
-rw-r--r--lib/prefix.c57
-rw-r--r--lib/prefix.h1
-rw-r--r--lib/routemap.c32
-rw-r--r--lib/routemap.h3
-rw-r--r--lib/routemap_cli.c7
-rw-r--r--lib/sockopt.c49
-rw-r--r--lib/sockopt.h22
-rw-r--r--lib/srv6.c33
-rw-r--r--lib/srv6.h23
-rw-r--r--lib/stream.h12
-rw-r--r--lib/subdir.am30
-rw-r--r--lib/thread.c2
-rw-r--r--lib/vty.c11
-rw-r--r--lib/vty.h9
-rw-r--r--lib/zclient.c76
-rw-r--r--lib/zclient.h17
-rw-r--r--lib/zebra.h4
-rw-r--r--lib/zlog_5424_cli.c2
-rw-r--r--nhrpd/nhrp_vty.c2
-rw-r--r--nhrpd/subdir.am1
-rw-r--r--ospf6d/ospf6_area.c14
-rw-r--r--ospf6d/ospf6_asbr.c26
-rw-r--r--ospf6d/ospf6_gr.c2
-rw-r--r--ospf6d/ospf6_gr_helper.c7
-rw-r--r--ospf6d/ospf6_interface.c18
-rw-r--r--ospf6d/ospf6_lsa.c2
-rw-r--r--ospf6d/ospf6_nssa.c2
-rw-r--r--ospf6d/ospf6_nssa.h2
-rw-r--r--ospf6d/ospf6_route.c8
-rw-r--r--ospf6d/ospf6_top.c2
-rw-r--r--ospf6d/ospf6d.c2
-rw-r--r--ospf6d/subdir.am21
-rw-r--r--ospfclient/ospf_apiclient.c9
-rw-r--r--ospfclient/ospf_apiclient.h5
-rw-r--r--ospfclient/ospfclient.c7
-rwxr-xr-xospfclient/ospfclient.py51
-rw-r--r--ospfd/ospf_abr.h2
-rw-r--r--ospfd/ospf_api.c7
-rw-r--r--ospfd/ospf_api.h17
-rw-r--r--ospfd/ospf_apiserver.c19
-rw-r--r--ospfd/ospf_dump.c491
-rw-r--r--ospfd/ospf_dump.h5
-rw-r--r--ospfd/ospf_flood.c12
-rw-r--r--ospfd/ospf_gr.c2
-rw-r--r--ospfd/ospf_interface.c11
-rw-r--r--ospfd/ospf_ldp_sync.c2
-rw-r--r--ospfd/ospf_lsa.c105
-rw-r--r--ospfd/ospf_lsa.h29
-rw-r--r--ospfd/ospf_lsdb.c9
-rw-r--r--ospfd/ospf_memory.c1
-rw-r--r--ospfd/ospf_memory.h1
-rw-r--r--ospfd/ospf_opaque.c11
-rw-r--r--ospfd/ospf_opaque.h2
-rw-r--r--ospfd/ospf_orr.c594
-rw-r--r--ospfd/ospf_orr.h58
-rw-r--r--ospfd/ospf_packet.c9
-rw-r--r--ospfd/ospf_route.c4
-rw-r--r--ospfd/ospf_route.h3
-rw-r--r--ospfd/ospf_spf.c201
-rw-r--r--ospfd/ospf_spf.h3
-rw-r--r--ospfd/ospf_vty.c145
-rw-r--r--ospfd/ospf_zebra.c7
-rw-r--r--ospfd/ospfd.c1
-rw-r--r--ospfd/ospfd.h10
-rw-r--r--ospfd/subdir.am14
-rw-r--r--pathd/path_cli.c54
-rw-r--r--pathd/path_pcep_cli.c2
-rw-r--r--pathd/path_ted.c10
-rw-r--r--pathd/path_ted.h1
-rw-r--r--pathd/pathd.c180
-rw-r--r--pathd/pathd.h7
-rw-r--r--pathd/subdir.am5
-rw-r--r--pbrd/pbr_debug.c2
-rw-r--r--pbrd/pbr_main.c5
-rw-r--r--pbrd/pbr_nht.c4
-rw-r--r--pbrd/pbr_nht.h1
-rw-r--r--pbrd/pbr_vty.c4
-rw-r--r--pbrd/subdir.am4
-rw-r--r--pceplib/pcep_msg_messages.c2
-rw-r--r--pceplib/pcep_msg_messages_encoding.c2
-rw-r--r--pceplib/pcep_pcc.c4
-rw-r--r--pceplib/pcep_pcc_api.c14
-rw-r--r--pceplib/pcep_session_logic.c6
-rw-r--r--pceplib/pcep_socket_comm.c6
-rw-r--r--pceplib/pcep_timers.c4
-rw-r--r--pceplib/pcep_utils_double_linked_list.c2
-rw-r--r--pceplib/pcep_utils_logging.c2
-rw-r--r--pceplib/pcep_utils_memory.c4
-rw-r--r--pceplib/pcep_utils_queue.c2
-rw-r--r--pimd/pim6_cmd.c110
-rw-r--r--pimd/pim6_cmd.h1
-rw-r--r--pimd/pim6_mld.c6
-rw-r--r--pimd/pim_br.c93
-rw-r--r--pimd/pim_br.h30
-rw-r--r--pimd/pim_cmd.c458
-rw-r--r--pimd/pim_cmd_common.c485
-rw-r--r--pimd/pim_cmd_common.h9
-rw-r--r--pimd/pim_iface.c4
-rw-r--r--pimd/pim_igmp_mtrace.c22
-rw-r--r--pimd/pim_memory.c1
-rw-r--r--pimd/pim_memory.h1
-rw-r--r--pimd/pim_mroute.c13
-rw-r--r--pimd/pim_mroute.h4
-rw-r--r--pimd/pim_nb_config.c3
-rw-r--r--pimd/pim_nht.c54
-rw-r--r--pimd/pim_nht.h7
-rw-r--r--pimd/pim_register.c16
-rw-r--r--pimd/pim_rp.c4
-rw-r--r--pimd/pim_rpf.c17
-rw-r--r--pimd/pim_tib.c3
-rw-r--r--pimd/pim_upstream.c3
-rw-r--r--pimd/pim_util.c12
-rw-r--r--pimd/pim_util.h1
-rw-r--r--pimd/pim_vty.c2
-rw-r--r--pimd/pim_zlookup.c2
-rw-r--r--pimd/subdir.am7
-rw-r--r--python/callgraph-dot.py34
-rw-r--r--python/clippy/__init__.py29
-rw-r--r--python/clippy/elf.py213
-rw-r--r--python/clippy/uidhash.py27
-rw-r--r--python/makefile.py11
-rw-r--r--python/runtests.py6
-rw-r--r--python/test_xrelfo.py21
-rw-r--r--python/tiabwarfo.py166
-rw-r--r--python/vtysh-cmd-check.py72
-rw-r--r--python/xref2vtysh.py389
-rw-r--r--python/xrelfo.py357
-rw-r--r--redhat/frr.pam1
-rw-r--r--redhat/frr.spec.in2
-rw-r--r--ripd/rip_cli.c2
-rw-r--r--ripd/rip_debug.c2
-rw-r--r--ripd/ripd.c8
-rw-r--r--ripd/subdir.am5
-rw-r--r--ripngd/ripng_cli.c2
-rw-r--r--ripngd/ripng_debug.c2
-rw-r--r--ripngd/ripngd.c7
-rw-r--r--ripngd/subdir.am5
-rw-r--r--sharpd/sharp_nht.c21
-rw-r--r--sharpd/sharp_vty.c12
-rw-r--r--sharpd/sharp_zebra.c3
-rw-r--r--sharpd/subdir.am1
-rw-r--r--snapcraft/snapcraft.yaml.in2
-rw-r--r--staticd/static_main.c1
-rw-r--r--staticd/static_vty.c4
-rw-r--r--staticd/subdir.am1
-rw-r--r--tests/isisd/test_isis_spf.refout180
-rw-r--r--tests/topotests/all_protocol_startup/r1/ospf6d.conf1
-rw-r--r--tests/topotests/all_protocol_startup/r1/ospfd.conf9
-rw-r--r--tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post4.1.ref4
-rw-r--r--tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post5.0.ref4
-rw-r--r--tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post6.1.ref4
-rw-r--r--tests/topotests/all_protocol_startup/r1/show_bgp_ipv4.ref4
-rw-r--r--tests/topotests/all_protocol_startup/r1/show_bgp_ipv6-post4.1.ref4
-rw-r--r--tests/topotests/all_protocol_startup/r1/show_bgp_ipv6.ref4
-rw-r--r--tests/topotests/all_protocol_startup/r1/show_bgp_ipv6_post6.1.ref4
-rw-r--r--tests/topotests/all_protocol_startup/r1/show_ip_ospf_interface.ref4
-rw-r--r--tests/topotests/all_protocol_startup/test_all_protocol_startup.py23
-rw-r--r--tests/topotests/bgp_accept_own/__init__.py0
-rw-r--r--tests/topotests/bgp_accept_own/ce1/bgpd.conf12
-rw-r--r--tests/topotests/bgp_accept_own/ce1/zebra.conf9
-rw-r--r--tests/topotests/bgp_accept_own/ce2/bgpd.conf12
-rw-r--r--tests/topotests/bgp_accept_own/ce2/zebra.conf9
-rw-r--r--tests/topotests/bgp_accept_own/pe1/bgpd.conf49
-rw-r--r--tests/topotests/bgp_accept_own/pe1/ldpd.conf12
-rw-r--r--tests/topotests/bgp_accept_own/pe1/ospfd.conf7
-rw-r--r--tests/topotests/bgp_accept_own/pe1/zebra.conf15
-rw-r--r--tests/topotests/bgp_accept_own/rr1/bgpd.conf25
-rw-r--r--tests/topotests/bgp_accept_own/rr1/ldpd.conf12
-rw-r--r--tests/topotests/bgp_accept_own/rr1/ospfd.conf7
-rw-r--r--tests/topotests/bgp_accept_own/rr1/zebra.conf9
-rw-r--r--tests/topotests/bgp_accept_own/test_bgp_accept_own.py198
-rw-r--r--tests/topotests/bgp_aigp/__init__.py0
-rw-r--r--tests/topotests/bgp_aigp/r1/bgpd.conf12
-rw-r--r--tests/topotests/bgp_aigp/r1/ospfd.conf17
-rw-r--r--tests/topotests/bgp_aigp/r1/zebra.conf10
-rw-r--r--tests/topotests/bgp_aigp/r2/bgpd.conf14
-rw-r--r--tests/topotests/bgp_aigp/r2/ospfd.conf13
-rw-r--r--tests/topotests/bgp_aigp/r2/zebra.conf10
-rw-r--r--tests/topotests/bgp_aigp/r3/bgpd.conf14
-rw-r--r--tests/topotests/bgp_aigp/r3/ospfd.conf13
-rw-r--r--tests/topotests/bgp_aigp/r3/zebra.conf10
-rw-r--r--tests/topotests/bgp_aigp/r4/bgpd.conf16
-rw-r--r--tests/topotests/bgp_aigp/r4/ospfd.conf13
-rw-r--r--tests/topotests/bgp_aigp/r4/zebra.conf10
-rw-r--r--tests/topotests/bgp_aigp/r5/bgpd.conf16
-rw-r--r--tests/topotests/bgp_aigp/r5/ospfd.conf13
-rw-r--r--tests/topotests/bgp_aigp/r5/zebra.conf10
-rw-r--r--tests/topotests/bgp_aigp/r6/bgpd.conf20
-rw-r--r--tests/topotests/bgp_aigp/r6/ospfd.conf17
-rw-r--r--tests/topotests/bgp_aigp/r6/zebra.conf13
-rw-r--r--tests/topotests/bgp_aigp/r7/bgpd.conf22
-rw-r--r--tests/topotests/bgp_aigp/r7/zebra.conf9
-rw-r--r--tests/topotests/bgp_aigp/test_bgp_aigp.py224
-rw-r--r--tests/topotests/bgp_basic_functionality_topo1/test_bgp_basic_functionality.py14
-rw-r--r--tests/topotests/bgp_communities_topo1/test_bgp_communities.py13
-rw-r--r--tests/topotests/bgp_communities_topo1/test_bgp_communities_topo2.py8
-rw-r--r--tests/topotests/bgp_conditional_advertisement_track_peer/__init__.py0
-rw-r--r--tests/topotests/bgp_conditional_advertisement_track_peer/r1/bgpd.conf17
-rw-r--r--tests/topotests/bgp_conditional_advertisement_track_peer/r1/zebra.conf6
-rw-r--r--tests/topotests/bgp_conditional_advertisement_track_peer/r2/bgpd.conf28
-rw-r--r--tests/topotests/bgp_conditional_advertisement_track_peer/r2/staticd.conf3
-rw-r--r--tests/topotests/bgp_conditional_advertisement_track_peer/r2/zebra.conf9
-rw-r--r--tests/topotests/bgp_conditional_advertisement_track_peer/r3/bgpd.conf10
-rw-r--r--tests/topotests/bgp_conditional_advertisement_track_peer/r3/zebra.conf9
-rw-r--r--tests/topotests/bgp_conditional_advertisement_track_peer/test_bgp_conditional_advertisement_track_peer.py154
-rw-r--r--tests/topotests/bgp_ecmp_topo2/test_ebgp_ecmp_topo2.py14
-rw-r--r--tests/topotests/bgp_ecmp_topo2/test_ibgp_ecmp_topo2.py14
-rw-r--r--tests/topotests/bgp_ecmp_topo3/test_ibgp_ecmp_topo3.py17
-rw-r--r--tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-1.py28
-rw-r--r--tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-2.py2
-rw-r--r--tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-3.py87
-rw-r--r--tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-4.py23
-rw-r--r--tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-1.py47
-rw-r--r--tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-2.py43
-rw-r--r--tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-3.py70
-rw-r--r--tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-4.py20
-rw-r--r--tests/topotests/bgp_gr_functionality_topo3/bgp_gr_functionality_topo3.py316
-rw-r--r--tests/topotests/bgp_gr_restart_retain_routes/r2/zebra.conf1
-rw-r--r--tests/topotests/bgp_gshut_topo1/test_ebgp_gshut_topo1.py2
-rw-r--r--tests/topotests/bgp_gshut_topo1/test_ibgp_gshut_topo1.py2
-rw-r--r--tests/topotests/bgp_local_asn/bgp_local_asn_agg.json147
-rw-r--r--tests/topotests/bgp_local_asn/bgp_local_asn_ecmp.json317
-rw-r--r--tests/topotests/bgp_local_asn/bgp_local_asn_topo1.json132
-rw-r--r--tests/topotests/bgp_local_asn/bgp_local_asn_topo2.json117
-rw-r--r--tests/topotests/bgp_local_asn/bgp_local_asn_vrf_topo1.json152
-rw-r--r--tests/topotests/bgp_local_asn/bgp_local_asn_vrf_topo2.json128
-rw-r--r--tests/topotests/bgp_local_asn/test_bgp_local_asn_agg.py420
-rw-r--r--tests/topotests/bgp_local_asn/test_bgp_local_asn_ecmp.py524
-rw-r--r--tests/topotests/bgp_local_asn/test_bgp_local_asn_topo1.py3655
-rw-r--r--tests/topotests/bgp_local_asn/test_bgp_local_asn_topo2.py699
-rw-r--r--tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo1.py1108
-rw-r--r--tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo2.py826
-rw-r--r--tests/topotests/bgp_max_med_on_startup/__init__.py0
-rw-r--r--tests/topotests/bgp_max_med_on_startup/r1/bgpd.conf11
-rw-r--r--tests/topotests/bgp_max_med_on_startup/r1/zebra.conf9
-rw-r--r--tests/topotests/bgp_max_med_on_startup/r2/bgpd.conf7
-rw-r--r--tests/topotests/bgp_max_med_on_startup/r2/zebra.conf6
-rw-r--r--tests/topotests/bgp_max_med_on_startup/test_bgp_max_med_on_startup.py114
-rw-r--r--tests/topotests/bgp_prefix_list_topo1/test_prefix_lists.py66
-rw-r--r--tests/topotests/bgp_route_map/test_route_map_topo1.py27
-rw-r--r--tests/topotests/bgp_route_map/test_route_map_topo2.py98
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/zebra.conf2
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/zebra.conf2
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/zebra.conf2
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/zebra.conf2
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce1/bgpd.conf8
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce1/ip_rib.json58
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce1/ipv6_rib.json58
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce1/zebra.conf16
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce2/bgpd.conf8
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce2/ip_rib.json58
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce2/ipv6_rib.json58
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce2/zebra.conf16
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce3/bgpd.conf8
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce3/ip_rib.json58
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce3/ipv6_rib.json58
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce3/zebra.conf16
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce4/bgpd.conf8
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce4/ip_rib.json58
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce4/ipv6_rib.json58
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce4/zebra.conf16
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce5/bgpd.conf8
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce5/ip_rib.json58
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce5/ipv6_rib.json58
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce5/zebra.conf16
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce6/bgpd.conf8
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce6/ip_rib.json58
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce6/ipv6_rib.json58
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce6/zebra.conf16
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/bgpd.conf87
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv4_rib.json167
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv4_rib_locator_deleted.json90
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv4_rib_locator_recreated.json166
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv4_rib_sid_vpn_export_disabled.json115
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv4_rib_sid_vpn_export_reenabled.json167
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv6_rib.json170
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv6_rib_locator_deleted.json160
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv6_rib_locator_recreated.json169
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv6_rib_sid_vpn_export_disabled.json116
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv6_rib_sid_vpn_export_reenabled.json170
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vrf10v4_rib.json86
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vrf10v6_rib.json86
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vrf20v4_rib.json92
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vrf20v6_rib.json92
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/zebra.conf43
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/bgpd.conf88
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv4_rib.json167
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv4_rib_locator_deleted.json90
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv4_rib_locator_recreated.json166
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv4_rib_sid_vpn_export_disabled.json117
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv4_rib_sid_vpn_export_reenabled.json167
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv6_rib.json170
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv6_rib_locator_deleted.json93
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv6_rib_locator_recreated.json169
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv6_rib_sid_vpn_export_disabled.json120
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv6_rib_sid_vpn_export_reenabled.json170
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vrf10v4_rib.json92
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vrf10v6_rib.json92
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vrf20v4_rib.json86
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vrf20v6_rib.json86
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/zebra.conf43
-rw-r--r--tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py362
-rw-r--r--tests/topotests/bgp_suppress_fib/r1/bgp_ipv4_allowas.json2
-rw-r--r--tests/topotests/bgp_suppress_fib/r2/bgp_ipv4_allowas.json2
-rw-r--r--tests/topotests/bgp_suppress_fib/r2/bgpd.conf2
-rw-r--r--tests/topotests/bgp_suppress_fib/r2/zebra.conf3
-rw-r--r--tests/topotests/bgp_suppress_fib/r3/v4_route3.json23
-rw-r--r--tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py14
-rw-r--r--tests/topotests/cspf_topo1/r1/zebra.conf1
-rw-r--r--tests/topotests/cspf_topo1/r2/zebra.conf1
-rw-r--r--tests/topotests/cspf_topo1/reference/sharp-ted.json280
-rw-r--r--tests/topotests/cspf_topo1/test_cspf_topo1.py102
-rw-r--r--tests/topotests/isis_lfa_topo1/rt1/bfdd.conf6
-rw-r--r--tests/topotests/isis_lfa_topo1/rt1/step14/show_ipv6_route.ref.diff0
-rw-r--r--tests/topotests/isis_lfa_topo1/rt1/step15/show_ipv6_route.ref.diff50
-rw-r--r--tests/topotests/isis_lfa_topo1/rt1/step16/show_ipv6_route.ref.diff53
-rw-r--r--tests/topotests/isis_lfa_topo1/rt2/bfdd.conf6
-rwxr-xr-xtests/topotests/isis_lfa_topo1/test_isis_lfa_topo1.py412
-rw-r--r--tests/topotests/isis_te_topo1/r1/zebra.conf1
-rw-r--r--tests/topotests/isis_te_topo1/r2/zebra.conf1
-rw-r--r--tests/topotests/isis_te_topo1/reference/ted_step1.json280
-rw-r--r--tests/topotests/isis_te_topo1/reference/ted_step2.json200
-rw-r--r--tests/topotests/isis_te_topo1/reference/ted_step3.json240
-rw-r--r--tests/topotests/isis_te_topo1/reference/ted_step4.json240
-rw-r--r--tests/topotests/isis_te_topo1/reference/ted_step5.json320
-rw-r--r--tests/topotests/isis_te_topo1/reference/ted_step6.json320
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt1/step10/show_ip_route.ref.diff0
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt1/step10/show_ipv6_route.ref.diff0
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt1/step10/show_mpls_table.ref.diff0
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt1/step11/show_ip_route.ref.diff0
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt1/step11/show_ipv6_route.ref.diff0
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt1/step11/show_mpls_table.ref.diff0
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt1/step12/show_ip_route.ref.diff19
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt1/step12/show_ipv6_route.ref.diff18
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt1/step12/show_mpls_table.ref.diff28
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt2/step10/show_ip_route.ref.diff0
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt2/step10/show_ipv6_route.ref.diff0
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt2/step10/show_mpls_table.ref.diff0
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt2/step11/show_ip_route.ref.diff0
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt2/step11/show_ipv6_route.ref.diff0
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt2/step11/show_mpls_table.ref.diff0
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt2/step12/show_ip_route.ref.diff0
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt2/step12/show_ipv6_route.ref.diff0
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt2/step12/show_mpls_table.ref.diff20
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt3/step10/show_ip_route.ref.diff0
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt3/step10/show_ipv6_route.ref.diff0
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt3/step10/show_mpls_table.ref.diff0
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt3/step11/show_ip_route.ref.diff0
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt3/step11/show_ipv6_route.ref.diff0
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt3/step11/show_mpls_table.ref.diff0
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt3/step12/show_ip_route.ref.diff58
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt3/step12/show_ipv6_route.ref.diff45
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt3/step12/show_mpls_table.ref.diff60
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt4/step10/show_ip_route.ref.diff0
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt4/step10/show_ipv6_route.ref.diff0
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt4/step10/show_mpls_table.ref.diff0
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt4/step11/show_ip_route.ref.diff0
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt4/step11/show_ipv6_route.ref.diff0
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt4/step11/show_mpls_table.ref.diff0
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt4/step12/show_ip_route.ref.diff144
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt4/step12/show_ipv6_route.ref.diff50
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt4/step12/show_mpls_table.ref.diff78
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt5/bfdd.conf14
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt5/step10/show_ip_route.ref.diff0
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt5/step10/show_ipv6_route.ref.diff0
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt5/step10/show_mpls_table.ref.diff0
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt5/step11/show_ip_route.ref.diff0
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt5/step11/show_ipv6_route.ref.diff0
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt5/step11/show_mpls_table.ref.diff0
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt5/step12/show_ip_route.ref.diff151
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt5/step12/show_ipv6_route.ref.diff53
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt5/step12/show_mpls_table.ref.diff80
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt6/bfdd.conf14
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt6/step10/show_ip_route.ref.diff0
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt6/step10/show_ipv6_route.ref.diff0
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt6/step10/show_mpls_table.ref.diff0
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt6/step11/show_ip_route.ref.diff125
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt6/step11/show_ipv6_route.ref.diff56
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt6/step11/show_mpls_table.ref.diff106
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt6/step12/show_ip_route.ref.diff153
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt6/step12/show_ipv6_route.ref.diff66
-rw-r--r--tests/topotests/isis_tilfa_topo1/rt6/step12/show_mpls_table.ref.diff78
-rwxr-xr-xtests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py367
-rw-r--r--tests/topotests/isis_topo1/test_isis_topo1.py313
-rw-r--r--tests/topotests/lib/bgp.py34
-rw-r--r--tests/topotests/lib/common_config.py160
-rw-r--r--tests/topotests/lib/pim.py1123
-rw-r--r--tests/topotests/multicast_pim6_static_rp_topo1/__init__.py0
-rw-r--r--tests/topotests/multicast_pim6_static_rp_topo1/multicast_pim6_static_rp.json (renamed from tests/topotests/multicast_pim_static_rp_topo1/multicast_pimv6_static_rp.json)0
-rwxr-xr-xtests/topotests/multicast_pim6_static_rp_topo1/test_multicast_pim6_static_rp1.py1321
-rwxr-xr-xtests/topotests/multicast_pim6_static_rp_topo1/test_multicast_pim6_static_rp2.py1324
-rwxr-xr-xtests/topotests/multicast_pim_static_rp_topo1/test_multicast_pimv6_static_rp.py414
-rw-r--r--tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py156
-rw-r--r--tests/topotests/ospf_te_topo1/r1/zebra.conf1
-rw-r--r--tests/topotests/ospf_te_topo1/r2/zebra.conf1
-rw-r--r--tests/topotests/ospf_te_topo1/reference/ted_step1.json180
-rw-r--r--tests/topotests/ospf_te_topo1/reference/ted_step2.json140
-rw-r--r--tests/topotests/ospf_te_topo1/reference/ted_step3.json120
-rw-r--r--tests/topotests/ospf_te_topo1/reference/ted_step4.json120
-rw-r--r--tests/topotests/ospf_te_topo1/reference/ted_step5.json160
-rw-r--r--tests/topotests/ospf_te_topo1/reference/ted_step6.json160
-rw-r--r--tests/topotests/ospf_te_topo1/reference/ted_step7.json120
-rw-r--r--tests/topotests/ospfapi/test_ospf_clientapi.py439
-rw-r--r--tests/topotests/pytest.ini1
-rw-r--r--tests/topotests/srv6_locator_custom_bits_length/__init__.py0
-rw-r--r--tests/topotests/srv6_locator_custom_bits_length/expected_chunks1.json1
-rw-r--r--tests/topotests/srv6_locator_custom_bits_length/expected_chunks2.json8
-rw-r--r--tests/topotests/srv6_locator_custom_bits_length/expected_chunks3.json1
-rw-r--r--tests/topotests/srv6_locator_custom_bits_length/expected_chunks4.json2
-rw-r--r--tests/topotests/srv6_locator_custom_bits_length/expected_chunks5.json2
-rw-r--r--tests/topotests/srv6_locator_custom_bits_length/expected_chunks6.json2
-rw-r--r--tests/topotests/srv6_locator_custom_bits_length/expected_locators1.json34
-rw-r--r--tests/topotests/srv6_locator_custom_bits_length/expected_locators2.json34
-rw-r--r--tests/topotests/srv6_locator_custom_bits_length/expected_locators3.json34
-rw-r--r--tests/topotests/srv6_locator_custom_bits_length/expected_locators4.json49
-rw-r--r--tests/topotests/srv6_locator_custom_bits_length/expected_locators5.json34
-rw-r--r--tests/topotests/srv6_locator_custom_bits_length/expected_locators6.json4
-rw-r--r--tests/topotests/srv6_locator_custom_bits_length/r1/setup.sh2
-rw-r--r--tests/topotests/srv6_locator_custom_bits_length/r1/sharpd.conf7
-rw-r--r--tests/topotests/srv6_locator_custom_bits_length/r1/zebra.conf22
-rwxr-xr-xtests/topotests/srv6_locator_custom_bits_length/test_srv6_locator.py160
-rw-r--r--tests/topotests/srv6_locator_usid/__init__.py0
-rw-r--r--tests/topotests/srv6_locator_usid/expected_chunks_1.json1
-rw-r--r--tests/topotests/srv6_locator_usid/expected_chunks_2.json8
-rw-r--r--tests/topotests/srv6_locator_usid/expected_chunks_3.json1
-rw-r--r--tests/topotests/srv6_locator_usid/expected_chunks_4.json1
-rw-r--r--tests/topotests/srv6_locator_usid/expected_chunks_5.json2
-rw-r--r--tests/topotests/srv6_locator_usid/expected_chunks_6.json2
-rw-r--r--tests/topotests/srv6_locator_usid/expected_chunks_7.json2
-rw-r--r--tests/topotests/srv6_locator_usid/expected_chunks_8.json2
-rw-r--r--tests/topotests/srv6_locator_usid/expected_locators_1.json20
-rw-r--r--tests/topotests/srv6_locator_usid/expected_locators_2.json20
-rw-r--r--tests/topotests/srv6_locator_usid/expected_locators_3.json20
-rw-r--r--tests/topotests/srv6_locator_usid/expected_locators_4.json35
-rw-r--r--tests/topotests/srv6_locator_usid/expected_locators_5.json36
-rw-r--r--tests/topotests/srv6_locator_usid/expected_locators_6.json35
-rw-r--r--tests/topotests/srv6_locator_usid/expected_locators_7.json19
-rw-r--r--tests/topotests/srv6_locator_usid/expected_locators_8.json4
-rw-r--r--tests/topotests/srv6_locator_usid/r1/setup.sh2
-rw-r--r--tests/topotests/srv6_locator_usid/r1/sharpd.conf7
-rw-r--r--tests/topotests/srv6_locator_usid/r1/zebra.conf20
-rwxr-xr-xtests/topotests/srv6_locator_usid/test_srv6_locator_usid.py276
-rw-r--r--tests/topotests/zebra_seg6local_route/r1/routes.json25
-rw-r--r--tests/topotests/zebra_seg6local_route/r1/setup.sh3
-rwxr-xr-xtests/topotests/zebra_seg6local_route/test_zebra_seg6local_route.py10
-rw-r--r--tools/etc/frr/support_bundle_commands.conf31
-rw-r--r--tools/etc/logrotate.d/frr (renamed from debian/frr.logrotate)0
-rwxr-xr-xtools/frr-reload.py35
-rwxr-xr-xtools/frr.in20
-rwxr-xr-xtools/frrcommon.sh.in18
-rw-r--r--tools/frrinit.sh.in2
-rw-r--r--tools/permutations.c3
-rw-r--r--vrrpd/subdir.am1
-rw-r--r--vrrpd/vrrp_vty.c12
-rw-r--r--vtysh/.gitignore4
-rwxr-xr-xvtysh/extract.pl.in282
-rw-r--r--vtysh/subdir.am21
-rw-r--r--vtysh/vtysh.c4
-rw-r--r--vtysh/vtysh_config.c39
-rw-r--r--watchfrr/subdir.am1
-rw-r--r--watchfrr/watchfrr.c24
-rw-r--r--watchfrr/watchfrr_vty.c4
-rw-r--r--yang/frr-bgp-route-map.yang15
-rw-r--r--yang/frr-isisd.yang22
-rw-r--r--zebra/debug.c5
-rw-r--r--zebra/dpdk/zebra_dplane_dpdk_vty.c2
-rw-r--r--zebra/dplane_fpm_nl.c14
-rw-r--r--zebra/interface.c85
-rw-r--r--zebra/main.c1
-rw-r--r--zebra/netconf_netlink.c2
-rw-r--r--zebra/rib.h7
-rw-r--r--zebra/rt_netlink.c93
-rw-r--r--zebra/rtadv.c2
-rw-r--r--zebra/subdir.am25
-rw-r--r--zebra/tc_netlink.c2
-rw-r--r--zebra/zapi_msg.c16
-rw-r--r--zebra/zebra_evpn_mh.c10
-rw-r--r--zebra/zebra_fpm.c29
-rw-r--r--zebra/zebra_mlag_vty.c2
-rw-r--r--zebra/zebra_nhg.c70
-rw-r--r--zebra/zebra_nhg.h4
-rw-r--r--zebra/zebra_rib.c17
-rw-r--r--zebra/zebra_routemap.c2
-rw-r--r--zebra/zebra_srte.c17
-rw-r--r--zebra/zebra_srte.h1
-rw-r--r--zebra/zebra_srv6.c52
-rw-r--r--zebra/zebra_srv6.h3
-rw-r--r--zebra/zebra_srv6_vty.c116
-rw-r--r--zebra/zebra_srv6_vty.h4
-rw-r--r--zebra/zebra_vrf.c2
-rw-r--r--zebra/zebra_vty.c11
624 files changed, 35147 insertions, 5796 deletions
diff --git a/.github/workflows/conflicts.yml b/.github/workflows/conflicts.yml
new file mode 100644
index 000000000..18a8c0d15
--- /dev/null
+++ b/.github/workflows/conflicts.yml
@@ -0,0 +1,21 @@
+name: Add a conflict label is PR needs to rebase
+
+on:
+ push:
+ pull_request_target:
+ types: [synchronize]
+
+jobs:
+ conflicts:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ pull-requests: write
+ steps:
+ - name: Check if PRs need a rebase (have some conflicts)
+ uses: eps1lon/actions-label-merge-conflict@releases/2.x
+ with:
+ dirtyLabel: "conflicts"
+ removeOnDirtyLabel: "no_conflicts"
+ repoToken: "${{ secrets.GITHUB_TOKEN }}"
+ commentOnDirty: "This pull request has conflicts, please resolve those before we can evaluate the pull request."
diff --git a/Makefile.am b/Makefile.am
index ce0f70a1a..44d2ab8e7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -144,7 +144,6 @@ pkginclude_HEADERS =
nodist_pkginclude_HEADERS =
dist_yangmodels_DATA =
man_MANS =
-vtysh_scan =
vtysh_daemons =
clippy_scan =
@@ -226,12 +225,13 @@ EXTRA_DIST += \
python/makefile.py \
python/tiabwarfo.py \
python/xrelfo.py \
+ python/xref2vtysh.py \
python/test_xrelfo.py \
python/runtests.py \
\
python/xrefstructs.json \
\
- redhat/frr.logrotate \
+ tools/etc/logrotate.d/frr \
redhat/frr.pam \
redhat/frr.spec \
\
diff --git a/alpine/APKBUILD.in b/alpine/APKBUILD.in
index 51986de2d..3aad9549b 100644
--- a/alpine/APKBUILD.in
+++ b/alpine/APKBUILD.in
@@ -15,8 +15,8 @@ makedepends="ncurses-dev net-snmp-dev gawk texinfo perl
libcap-dev libcurl libedit libffi libgcc libgomp libisoburn libisofs
libltdl libressl libssh2 libstdc++ libtool libuuid
linux-headers lzip lzo m4 make mkinitfs mpc1 mpfr4 mtools musl-dev
- ncurses-libs ncurses-terminfo ncurses-terminfo-base patch pax-utils pcre
- perl pkgconf python3 python3-dev readline readline-dev sqlite-libs
+ ncurses-libs ncurses-terminfo ncurses-terminfo-base patch pax-utils pcre2
+ perl pkgconf python3 python3-dev readline readline-dev sqlite-libs pcre2-dev
squashfs-tools sudo tar texinfo xorriso xz-libs py-pip rtrlib rtrlib-dev
py3-sphinx elfutils elfutils-dev libyang-dev"
checkdepends="pytest py-setuptools"
@@ -46,8 +46,9 @@ build() {
--enable-multipath=64 \
--enable-vty-group=frrvty \
--enable-user=$_user \
- --enable-group=$_user
- make
+ --enable-group=$_user \
+ --enable-pcre2posix
+ make -j $(nproc)
}
check() {
diff --git a/babeld/babel_zebra.c b/babeld/babel_zebra.c
index d0da93e50..daaa870a6 100644
--- a/babeld/babel_zebra.c
+++ b/babeld/babel_zebra.c
@@ -225,6 +225,8 @@ DEFUN_NOSH (show_debugging_babel,
debug_babel_config_write(vty);
+ cmd_show_lib_debugs(vty);
+
return CMD_SUCCESS;
}
diff --git a/babeld/subdir.am b/babeld/subdir.am
index 856cbd13e..4b9037283 100644
--- a/babeld/subdir.am
+++ b/babeld/subdir.am
@@ -4,11 +4,6 @@
if BABELD
sbin_PROGRAMS += babeld/babeld
-vtysh_scan += \
- babeld/babel_interface.c \
- babeld/babel_zebra.c \
- babeld/babeld.c \
- # end
vtysh_daemons += babeld
endif
diff --git a/bfdd/bfdd_cli.c b/bfdd/bfdd_cli.c
index 69424c45d..52f2dd8fd 100644
--- a/bfdd/bfdd_cli.c
+++ b/bfdd/bfdd_cli.c
@@ -26,9 +26,7 @@
#include "lib/log.h"
#include "lib/northbound_cli.h"
-#ifndef VTYSH_EXTRACT_PL
#include "bfdd/bfdd_cli_clippy.c"
-#endif /* VTYSH_EXTRACT_PL */
#include "bfd.h"
#include "bfdd_nb.h"
diff --git a/bfdd/bfdd_vty.c b/bfdd/bfdd_vty.c
index 21429f06c..7b7a001e2 100644
--- a/bfdd/bfdd_vty.c
+++ b/bfdd/bfdd_vty.c
@@ -28,9 +28,7 @@
#include "bfd.h"
-#ifndef VTYSH_EXTRACT_PL
#include "bfdd/bfdd_vty_clippy.c"
-#endif
/*
* Commands help string definitions.
@@ -973,6 +971,8 @@ DEFUN_NOSH(show_debugging_bfd,
if (bglobal.debug_network)
vty_out(vty, " Network layer debugging is on.\n");
+ cmd_show_lib_debugs(vty);
+
return CMD_SUCCESS;
}
diff --git a/bfdd/subdir.am b/bfdd/subdir.am
index 8d35b933d..b86a18967 100644
--- a/bfdd/subdir.am
+++ b/bfdd/subdir.am
@@ -5,8 +5,6 @@
if BFDD
noinst_LIBRARIES += bfdd/libbfd.a
sbin_PROGRAMS += bfdd/bfdd
-vtysh_scan += bfdd/bfdd_vty.c
-vtysh_scan += bfdd/bfdd_cli.c
vtysh_daemons += bfdd
man8 += $(MANBUILD)/frr-bfdd.8
endif
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c
index b7d0958ba..89aed1ba6 100644
--- a/bgpd/bgp_attr.c
+++ b/bgpd/bgp_attr.c
@@ -83,6 +83,7 @@ static const struct message attr_str[] = {
{BGP_ATTR_LARGE_COMMUNITIES, "LARGE_COMMUNITY"},
{BGP_ATTR_PREFIX_SID, "PREFIX_SID"},
{BGP_ATTR_IPV6_EXT_COMMUNITIES, "IPV6_EXT_COMMUNITIES"},
+ {BGP_ATTR_AIGP, "AIGP"},
{0}};
static const struct message attr_flag_str[] = {
@@ -448,6 +449,110 @@ static void transit_unintern(struct transit **transit)
}
}
+static bool bgp_attr_aigp_get_tlv_metric(uint8_t *pnt, int length,
+ uint64_t *aigp)
+{
+ uint8_t *data = pnt;
+ uint8_t tlv_type;
+ uint16_t tlv_length;
+
+ while (length) {
+ tlv_type = *data;
+ ptr_get_be16(data + 1, &tlv_length);
+ (void)data;
+
+ /* The value field of the AIGP TLV is always 8 octets
+ * long and its value is interpreted as an unsigned 64-bit
+ * integer.
+ */
+ if (tlv_type == BGP_AIGP_TLV_METRIC) {
+ (void)ptr_get_be64(data + 3, aigp);
+
+ /* If an AIGP attribute is received and its first AIGP
+ * TLV contains the maximum value 0xffffffffffffffff,
+ * the attribute SHOULD be considered to be malformed
+ * and SHOULD be discarded as specified in this section.
+ */
+ if (*aigp == BGP_AIGP_TLV_METRIC_MAX) {
+ zlog_err("Bad AIGP TLV (%s) length: %llu",
+ BGP_AIGP_TLV_METRIC_DESC,
+ BGP_AIGP_TLV_METRIC_MAX);
+ return false;
+ }
+
+ return true;
+ }
+
+ data += tlv_length;
+ length -= tlv_length;
+ }
+
+ return false;
+}
+
+static uint64_t bgp_aigp_metric_total(struct bgp_path_info *bpi)
+{
+ uint64_t aigp = bgp_attr_get_aigp_metric(bpi->attr);
+
+ if (bpi->nexthop)
+ return aigp + bpi->nexthop->metric;
+ else
+ return aigp;
+}
+
+static void stream_put_bgp_aigp_tlv_metric(struct stream *s,
+ struct bgp_path_info *bpi)
+{
+ stream_putc(s, BGP_AIGP_TLV_METRIC);
+ stream_putw(s, BGP_AIGP_TLV_METRIC_LEN);
+ stream_putq(s, bgp_aigp_metric_total(bpi));
+}
+
+static bool bgp_attr_aigp_valid(uint8_t *pnt, int length)
+{
+ uint8_t *data = pnt;
+ uint8_t tlv_type;
+ uint16_t tlv_length;
+
+ if (length < 3) {
+ zlog_err("Bad AIGP attribute length (MUST be minimum 3): %u",
+ length);
+ return false;
+ }
+
+ while (length) {
+ tlv_type = *data;
+ ptr_get_be16(data + 1, &tlv_length);
+ (void)data;
+
+ if (length < tlv_length) {
+ zlog_err(
+ "Bad AIGP attribute length: %u, but TLV length: %u",
+ length, tlv_length);
+ return false;
+ }
+
+ if (tlv_length < 3) {
+ zlog_err("Bad AIGP TLV length (MUST be minimum 3): %u",
+ tlv_length);
+ return false;
+ }
+
+ /* AIGP TLV, Length: 11 */
+ if (tlv_type == BGP_AIGP_TLV_METRIC &&
+ tlv_length != BGP_AIGP_TLV_METRIC_LEN) {
+ zlog_err("Bad AIGP TLV (%s) length: %u",
+ BGP_AIGP_TLV_METRIC_DESC, tlv_length);
+ return false;
+ }
+
+ data += tlv_length;
+ length -= tlv_length;
+ }
+
+ return true;
+}
+
static void *srv6_l3vpn_hash_alloc(void *p)
{
return p;
@@ -702,6 +807,7 @@ unsigned int attrhash_key_make(const void *p)
MIX(attr->nh_type);
MIX(attr->bh_type);
MIX(attr->otc);
+ MIX(bgp_attr_get_aigp_metric(attr));
return key;
}
@@ -736,6 +842,8 @@ bool attrhash_cmp(const void *p1, const void *p2)
== bgp_attr_get_cluster(attr2)
&& bgp_attr_get_transit(attr1)
== bgp_attr_get_transit(attr2)
+ && bgp_attr_get_aigp_metric(attr1)
+ == bgp_attr_get_aigp_metric(attr2)
&& attr1->rmap_table_id == attr2->rmap_table_id
&& (attr1->encap_tunneltype == attr2->encap_tunneltype)
&& encap_same(attr1->encap_subtlvs, attr2->encap_subtlvs)
@@ -1387,6 +1495,7 @@ const uint8_t attr_flags_values[] = {
[BGP_ATTR_PREFIX_SID] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
[BGP_ATTR_IPV6_EXT_COMMUNITIES] =
BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
+ [BGP_ATTR_AIGP] = BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS,
};
static const size_t attr_flags_values_max = array_size(attr_flags_values) - 1;
@@ -3053,6 +3162,45 @@ bgp_attr_pmsi_tunnel(struct bgp_attr_parser_args *args)
return BGP_ATTR_PARSE_PROCEED;
}
+/* AIGP attribute (rfc7311) */
+static enum bgp_attr_parse_ret bgp_attr_aigp(struct bgp_attr_parser_args *args)
+{
+ struct peer *const peer = args->peer;
+ struct attr *const attr = args->attr;
+ const bgp_size_t length = args->length;
+ uint8_t *s = stream_pnt(peer->curr);
+ uint64_t aigp = 0;
+
+ /* If an AIGP attribute is received on a BGP session for which
+ * AIGP_SESSION is disabled, the attribute MUST be treated exactly
+ * as if it were an unrecognized non-transitive attribute.
+ * That is, it "MUST be quietly ignored and not passed along to
+ * other BGP peers".
+ * For Internal BGP (IBGP) sessions, and for External BGP (EBGP)
+ * sessions between members of the same BGP Confederation,
+ * the default value of AIGP_SESSION SHOULD be "enabled".
+ */
+ if (peer->sort == BGP_PEER_EBGP &&
+ !CHECK_FLAG(peer->flags, PEER_FLAG_AIGP)) {
+ zlog_warn(
+ "%pBP received AIGP attribute, but eBGP peer do not support it",
+ peer);
+ goto aigp_ignore;
+ }
+
+ if (!bgp_attr_aigp_valid(s, length))
+ goto aigp_ignore;
+
+ /* Extract AIGP Metric TLV */
+ if (bgp_attr_aigp_get_tlv_metric(s, length, &aigp))
+ bgp_attr_set_aigp_metric(attr, aigp);
+
+aigp_ignore:
+ stream_forward_getp(peer->curr, length);
+
+ return BGP_ATTR_PARSE_PROCEED;
+}
+
/* OTC attribute. */
static enum bgp_attr_parse_ret bgp_attr_otc(struct bgp_attr_parser_args *args)
{
@@ -3431,6 +3579,9 @@ enum bgp_attr_parse_ret bgp_attr_parse(struct peer *peer, struct attr *attr,
case BGP_ATTR_OTC:
ret = bgp_attr_otc(&attr_args);
break;
+ case BGP_ATTR_AIGP:
+ ret = bgp_attr_aigp(&attr_args);
+ break;
default:
ret = bgp_attr_unknown(&attr_args);
break;
@@ -3951,7 +4102,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
struct prefix *p, afi_t afi, safi_t safi,
struct peer *from, struct prefix_rd *prd,
mpls_label_t *label, uint32_t num_labels,
- bool addpath_capable, uint32_t addpath_tx_id)
+ bool addpath_capable, uint32_t addpath_tx_id,
+ struct bgp_path_info *bpi)
{
size_t cp;
size_t aspath_sizep;
@@ -4355,7 +4507,9 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
stream_put(s, &attr->srv6_l3vpn->sid,
sizeof(attr->srv6_l3vpn->sid)); /* sid */
stream_putc(s, 0); /* sid_flags */
- stream_putw(s, 0xffff); /* endpoint */
+ stream_putw(s,
+ attr->srv6_l3vpn
+ ->endpoint_behavior); /* endpoint */
stream_putc(s, 0); /* reserved */
stream_putc(
s,
@@ -4457,6 +4611,22 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
stream_putl(s, attr->otc);
}
+ /* AIGP */
+ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AIGP) &&
+ (CHECK_FLAG(peer->flags, PEER_FLAG_AIGP) ||
+ peer->sort != BGP_PEER_EBGP)) {
+ /* At the moment only AIGP Metric TLV exists for AIGP
+ * attribute. If more comes in, do not forget to update
+ * attr_len variable to include new ones.
+ */
+ uint8_t attr_len = BGP_AIGP_TLV_METRIC_LEN;
+
+ stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
+ stream_putc(s, BGP_ATTR_AIGP);
+ stream_putc(s, attr_len);
+ stream_put_bgp_aigp_tlv_metric(s, bpi);
+ }
+
/* Unknown transit attribute. */
struct transit *transit = bgp_attr_get_transit(attr);
@@ -4540,7 +4710,7 @@ void bgp_attr_finish(void)
}
/* Make attribute packet. */
-void bgp_dump_routes_attr(struct stream *s, struct attr *attr,
+void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
const struct prefix *prefix)
{
unsigned long cp;
@@ -4549,6 +4719,7 @@ void bgp_dump_routes_attr(struct stream *s, struct attr *attr,
struct aspath *aspath;
bool addpath_capable = false;
uint32_t addpath_tx_id = 0;
+ struct attr *attr = bpi->attr;
/* Remember current pointer. */
cp = stream_get_endp(s);
@@ -4712,6 +4883,20 @@ void bgp_dump_routes_attr(struct stream *s, struct attr *attr,
stream_putl(s, attr->otc);
}
+ /* AIGP */
+ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AIGP)) {
+ /* At the moment only AIGP Metric TLV exists for AIGP
+ * attribute. If more comes in, do not forget to update
+ * attr_len variable to include new ones.
+ */
+ uint8_t attr_len = BGP_AIGP_TLV_METRIC_LEN;
+
+ stream_putc(s, BGP_ATTR_FLAG_OPTIONAL | BGP_ATTR_FLAG_TRANS);
+ stream_putc(s, BGP_ATTR_AIGP);
+ stream_putc(s, attr_len);
+ stream_put_bgp_aigp_tlv_metric(s, bpi);
+ }
+
/* Return total size of attribute. */
len = stream_get_endp(s) - cp - 2;
stream_putw_at(s, cp, len);
diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h
index 4963ea64d..bc82d0c6e 100644
--- a/bgpd/bgp_attr.h
+++ b/bgpd/bgp_attr.h
@@ -80,14 +80,6 @@
#define BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE 1
#define BGP_PREFIX_SID_SRV6_L3_SERVICE_SID_STRUCTURE_LENGTH 6
-/* SRv6 SID Structure default values */
-#define BGP_PREFIX_SID_SRV6_LOCATOR_BLOCK_LENGTH 40
-#define BGP_PREFIX_SID_SRV6_LOCATOR_NODE_LENGTH 24
-#define BGP_PREFIX_SID_SRV6_FUNCTION_LENGTH 16
-#define BGP_PREFIX_SID_SRV6_ARGUMENT_LENGTH 0
-#define BGP_PREFIX_SID_SRV6_TRANSPOSITION_LENGTH 16
-#define BGP_PREFIX_SID_SRV6_TRANSPOSITION_OFFSET 64
-
#define BGP_ATTR_NH_AFI(afi, attr) \
((afi != AFI_L2VPN) ? afi : \
((attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV4) ? AFI_IP : AFI_IP6))
@@ -337,6 +329,9 @@ struct attr {
/* OTC value if set */
uint32_t otc;
+
+ /* AIGP Metric */
+ uint64_t aigp_metric;
};
/* rmap_change_flags definition */
@@ -404,15 +399,13 @@ extern struct attr *bgp_attr_aggregate_intern(
struct community *community, struct ecommunity *ecommunity,
struct lcommunity *lcommunity, struct bgp_aggregate *aggregate,
uint8_t atomic_aggregate, const struct prefix *p);
-extern bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer,
- struct stream *s, struct attr *attr,
- struct bpacket_attr_vec_arr *vecarr,
- struct prefix *p, afi_t afi, safi_t safi,
- struct peer *from, struct prefix_rd *prd,
- mpls_label_t *label, uint32_t num_labels,
- bool addpath_capable,
- uint32_t addpath_tx_id);
-extern void bgp_dump_routes_attr(struct stream *s, struct attr *attr,
+extern bgp_size_t bgp_packet_attribute(
+ struct bgp *bgp, struct peer *peer, struct stream *s, struct attr *attr,
+ struct bpacket_attr_vec_arr *vecarr, struct prefix *p, afi_t afi,
+ safi_t safi, struct peer *from, struct prefix_rd *prd,
+ mpls_label_t *label, uint32_t num_labels, bool addpath_capable,
+ uint32_t addpath_tx_id, struct bgp_path_info *bpi);
+extern void bgp_dump_routes_attr(struct stream *s, struct bgp_path_info *bpi,
const struct prefix *p);
extern bool attrhash_cmp(const void *arg1, const void *arg2);
extern unsigned int attrhash_key_make(const void *p);
@@ -593,6 +586,19 @@ static inline void bgp_attr_set_transit(struct attr *attr,
attr->transit = transit;
}
+static inline uint64_t bgp_attr_get_aigp_metric(const struct attr *attr)
+{
+ return attr->aigp_metric;
+}
+
+static inline void bgp_attr_set_aigp_metric(struct attr *attr, uint64_t aigp)
+{
+ attr->aigp_metric = aigp;
+
+ if (aigp)
+ attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AIGP);
+}
+
static inline struct cluster_list *bgp_attr_get_cluster(const struct attr *attr)
{
return attr->cluster1;
diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c
index bcab4099c..2a65dbac8 100644
--- a/bgpd/bgp_bmp.c
+++ b/bgpd/bgp_bmp.c
@@ -853,8 +853,9 @@ static struct stream *bmp_update(const struct prefix *p, struct prefix_rd *prd,
stream_putw(s, 0);
/* 5: Encode all the attributes, except MP_REACH_NLRI attr. */
- total_attr_len = bgp_packet_attribute(NULL, peer, s, attr,
- &vecarr, NULL, afi, safi, peer, NULL, NULL, 0, 0, 0);
+ total_attr_len =
+ bgp_packet_attribute(NULL, peer, s, attr, &vecarr, NULL, afi,
+ safi, peer, NULL, NULL, 0, 0, 0, NULL);
/* space check? */
@@ -2033,9 +2034,7 @@ static const struct cmd_variable_handler bmp_targets_var_handlers[] = {
#define BMP_STR "BGP Monitoring Protocol\n"
-#ifndef VTYSH_EXTRACT_PL
#include "bgpd/bgp_bmp_clippy.c"
-#endif
DEFPY_NOSH(bmp_targets_main,
bmp_targets_cmd,
diff --git a/bgpd/bgp_community.h b/bgpd/bgp_community.h
index 616ddb440..05a5d4486 100644
--- a/bgpd/bgp_community.h
+++ b/bgpd/bgp_community.h
@@ -23,6 +23,7 @@
#include "lib/json.h"
#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_attr.h"
/* Communities attribute. */
struct community {
@@ -109,4 +110,30 @@ extern void bgp_remove_comm_from_aggregate_hash(struct bgp_aggregate *aggregate,
struct community *community);
extern void bgp_aggr_community_remove(void *arg);
+/* This implies that when propagating routes into a VRF, the ACCEPT_OWN
+ * community SHOULD NOT be propagated.
+ */
+static inline void community_strip_accept_own(struct attr *attr)
+{
+ struct community *old_com = bgp_attr_get_community(attr);
+ struct community *new_com = NULL;
+ uint32_t val = COMMUNITY_ACCEPT_OWN;
+
+ if (old_com && community_include(old_com, val)) {
+ new_com = community_dup(old_com);
+ val = htonl(val);
+ community_del_val(new_com, &val);
+
+ if (!old_com->refcnt)
+ community_free(&old_com);
+
+ if (!new_com->size) {
+ community_free(&new_com);
+ bgp_attr_set_community(attr, NULL);
+ } else {
+ bgp_attr_set_community(attr, new_com);
+ }
+ }
+}
+
#endif /* _QUAGGA_BGP_COMMUNITY_H */
diff --git a/bgpd/bgp_conditional_adv.c b/bgpd/bgp_conditional_adv.c
index 2598361ad..4ad00ed12 100644
--- a/bgpd/bgp_conditional_adv.c
+++ b/bgpd/bgp_conditional_adv.c
@@ -176,6 +176,7 @@ static void bgp_conditional_adv_timer(struct thread *t)
struct listnode *node, *nnode = NULL;
struct update_subgroup *subgrp = NULL;
route_map_result_t ret;
+ bool advmap_table_changed = false;
bgp = THREAD_ARG(t);
assert(bgp);
@@ -183,6 +184,20 @@ static void bgp_conditional_adv_timer(struct thread *t)
thread_add_timer(bm->master, bgp_conditional_adv_timer, bgp,
bgp->condition_check_period, &bgp->t_condition_check);
+ /* loop through each peer and check if we have peers with
+ * advmap_table_change attribute set, to make sure we send
+ * conditional advertisements properly below.
+ * peer->advmap_table_change is added on incoming BGP UPDATES,
+ * but here it's used for outgoing UPDATES, hence we need to
+ * check if at least one peer got advmap_table_change.
+ */
+ for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) {
+ if (peer->advmap_table_change) {
+ advmap_table_changed = true;
+ break;
+ }
+ }
+
/* loop through each peer and advertise or withdraw routes if
* advertise-map is configured and prefix(es) in condition-map
* does exist(exist-map)/not exist(non-exist-map) in BGP table
@@ -217,8 +232,8 @@ static void bgp_conditional_adv_timer(struct thread *t)
|| !filter->advmap.amap || !filter->advmap.cmap)
continue;
- if (!peer->advmap_config_change[afi][safi]
- && !peer->advmap_table_change)
+ if (!peer->advmap_config_change[afi][safi] &&
+ !advmap_table_changed)
continue;
if (BGP_DEBUG(cond_adv, COND_ADV)) {
diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c
index df7262be6..92a22d71b 100644
--- a/bgpd/bgp_debug.c
+++ b/bgpd/bgp_debug.c
@@ -71,6 +71,7 @@ unsigned long conf_bgp_debug_graceful_restart;
unsigned long conf_bgp_debug_evpn_mh;
unsigned long conf_bgp_debug_bfd;
unsigned long conf_bgp_debug_cond_adv;
+unsigned long conf_bgp_debug_optimal_route_reflection;
unsigned long term_bgp_debug_as4;
unsigned long term_bgp_debug_neighbor_events;
@@ -92,6 +93,7 @@ unsigned long term_bgp_debug_graceful_restart;
unsigned long term_bgp_debug_evpn_mh;
unsigned long term_bgp_debug_bfd;
unsigned long term_bgp_debug_cond_adv;
+unsigned long term_bgp_debug_optimal_route_reflection;
struct list *bgp_debug_neighbor_events_peers = NULL;
struct list *bgp_debug_keepalive_peers = NULL;
@@ -410,6 +412,11 @@ bool bgp_dump_attr(struct attr *attr, char *buf, size_t size)
snprintf(buf + strlen(buf), size - strlen(buf),
", localpref %u", attr->local_pref);
+ if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AIGP)))
+ snprintf(buf + strlen(buf), size - strlen(buf),
+ ", aigp-metric %" PRIu64,
+ (unsigned long long)bgp_attr_get_aigp_metric(attr));
+
if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC)))
snprintf(buf + strlen(buf), size - strlen(buf), ", metric %u",
attr->med);
@@ -1408,9 +1415,7 @@ DEFUN (no_debug_bgp_update_direct_peer,
return CMD_SUCCESS;
}
-#ifndef VTYSH_EXTRACT_PL
#include "bgpd/bgp_debug_clippy.c"
-#endif
DEFPY (debug_bgp_update_prefix_afi_safi,
debug_bgp_update_prefix_afi_safi_cmd,
@@ -2044,6 +2049,33 @@ DEFPY (debug_bgp_evpn_mh,
return CMD_SUCCESS;
}
+DEFPY (debug_bgp_optimal_route_reflection,
+ debug_bgp_optimal_route_reflection_cmd,
+ "[no$no] debug bgp optimal-route-reflection",
+ NO_STR
+ DEBUG_STR
+ BGP_STR
+ BGP_ORR_DEBUG)
+{
+ if (vty->node == CONFIG_NODE) {
+ if (no)
+ DEBUG_OFF(optimal_route_reflection, ORR);
+ else
+ DEBUG_ON(optimal_route_reflection, ORR);
+ } else {
+ if (no) {
+ TERM_DEBUG_OFF(optimal_route_reflection, ORR);
+ vty_out(vty,
+ "BGP Optimal Route Reflection debugging is off\n");
+ } else {
+ TERM_DEBUG_ON(optimal_route_reflection, ORR);
+ vty_out(vty,
+ "BGP Optimal Route Reflection debugging is on\n");
+ }
+ }
+ return CMD_SUCCESS;
+}
+
DEFUN (debug_bgp_labelpool,
debug_bgp_labelpool_cmd,
"debug bgp labelpool",
@@ -2182,6 +2214,7 @@ DEFUN (no_debug_bgp,
TERM_DEBUG_OFF(evpn_mh, EVPN_MH_RT);
TERM_DEBUG_OFF(bfd, BFD_LIB);
TERM_DEBUG_OFF(cond_adv, COND_ADV);
+ TERM_DEBUG_OFF(optimal_route_reflection, ORR);
vty_out(vty, "All possible debugging has been turned off\n");
@@ -2278,6 +2311,12 @@ DEFUN_NOSH (show_debugging_bgp,
vty_out(vty,
" BGP conditional advertisement debugging is on\n");
+ if (BGP_DEBUG(optimal_route_reflection, ORR))
+ vty_out(vty,
+ " BGP Optimal Route Reflection debugging is on\n");
+
+ cmd_show_lib_debugs(vty);
+
return CMD_SUCCESS;
}
@@ -2412,6 +2451,11 @@ static int bgp_config_write_debug(struct vty *vty)
write++;
}
+ if (CONF_BGP_DEBUG(optimal_route_reflection, ORR)) {
+ vty_out(vty, "debug bgp optimal-route-reflection\n");
+ write++;
+ }
+
return write;
}
@@ -2544,6 +2588,10 @@ void bgp_debug_init(void)
/* debug bgp conditional advertisement */
install_element(ENABLE_NODE, &debug_bgp_cond_adv_cmd);
install_element(CONFIG_NODE, &debug_bgp_cond_adv_cmd);
+
+ /* debug bgp optimal route reflection */
+ install_element(ENABLE_NODE, &debug_bgp_optimal_route_reflection_cmd);
+ install_element(CONFIG_NODE, &debug_bgp_optimal_route_reflection_cmd);
}
/* Return true if this prefix is on the per_prefix_list of prefixes to debug
diff --git a/bgpd/bgp_debug.h b/bgpd/bgp_debug.h
index be5ed0afd..f7090260a 100644
--- a/bgpd/bgp_debug.h
+++ b/bgpd/bgp_debug.h
@@ -81,6 +81,7 @@ extern unsigned long conf_bgp_debug_graceful_restart;
extern unsigned long conf_bgp_debug_evpn_mh;
extern unsigned long conf_bgp_debug_bfd;
extern unsigned long conf_bgp_debug_cond_adv;
+extern unsigned long conf_bgp_debug_optimal_route_reflection;
extern unsigned long term_bgp_debug_as4;
extern unsigned long term_bgp_debug_neighbor_events;
@@ -100,6 +101,7 @@ extern unsigned long term_bgp_debug_graceful_restart;
extern unsigned long term_bgp_debug_evpn_mh;
extern unsigned long term_bgp_debug_bfd;
extern unsigned long term_bgp_debug_cond_adv;
+extern unsigned long term_bgp_debug_optimal_route_reflection;
extern struct list *bgp_debug_neighbor_events_peers;
extern struct list *bgp_debug_keepalive_peers;
@@ -138,6 +140,7 @@ struct bgp_debug_filter {
#define BGP_DEBUG_PBR_ERROR 0x02
#define BGP_DEBUG_EVPN_MH_ES 0x01
#define BGP_DEBUG_EVPN_MH_RT 0x02
+#define BGP_DEBUG_ORR 0x01
#define BGP_DEBUG_PACKET_SEND 0x01
#define BGP_DEBUG_PACKET_SEND_DETAIL 0x02
diff --git a/bgpd/bgp_dump.c b/bgpd/bgp_dump.c
index 11e84f00b..254996eda 100644
--- a/bgpd/bgp_dump.c
+++ b/bgpd/bgp_dump.c
@@ -376,7 +376,7 @@ bgp_dump_route_node_record(int afi, struct bgp_dest *dest,
/* Dump attribute. */
/* Skip prefix & AFI/SAFI for MP_NLRI */
- bgp_dump_routes_attr(obuf, path->attr, p);
+ bgp_dump_routes_attr(obuf, path, p);
cur_endp = stream_get_endp(obuf);
if (cur_endp > BGP_STANDARD_MESSAGE_MAX_PACKET_SIZE
diff --git a/bgpd/bgp_errors.c b/bgpd/bgp_errors.c
index 9f87f8ce7..8bc2dbca7 100644
--- a/bgpd/bgp_errors.c
+++ b/bgpd/bgp_errors.c
@@ -236,6 +236,12 @@ static struct log_ref ferr_bgp_err[] = {
.suggestion = "Determine the source of the update and determine why the PMSI tunnel attribute length has been set incorrectly"
},
{
+ .code = EC_BGP_ATTR_AIGP,
+ .title = "BGP AIGP attribute is incorrect",
+ .description = "BGP AIGP attribute is incorrect",
+ .suggestion = "Determine the source of the attribute and determine why the AIGP attribute has been set incorrectly"
+ },
+ {
.code = EC_BGP_PEER_GROUP,
.title = "BGP peergroup operated on in error",
.description = "BGP operating on peer-group instead of peers included",
diff --git a/bgpd/bgp_errors.h b/bgpd/bgp_errors.h
index 0c0917c49..4986c314a 100644
--- a/bgpd/bgp_errors.h
+++ b/bgpd/bgp_errors.h
@@ -34,6 +34,7 @@ enum bgp_log_refs {
EC_BGP_ATTR_PMSI_TYPE,
EC_BGP_ATTR_PMSI_LEN,
EC_BGP_ATTR_NH_SEND_LEN,
+ EC_BGP_ATTR_AIGP,
EC_BGP_PEER_GROUP,
EC_BGP_PEER_DELETE,
EC_BGP_TABLE_CHUNK,
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index 90e04a042..eab70bfda 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -62,6 +62,7 @@
DEFINE_QOBJ_TYPE(bgpevpn);
DEFINE_QOBJ_TYPE(bgp_evpn_es);
+DEFINE_MTYPE_STATIC(BGPD, VRF_ROUTE_TARGET, "L3 Route Target");
/*
* Static function declarations
@@ -349,6 +350,15 @@ int bgp_evpn_route_target_cmp(struct ecommunity *ecom1,
return strcmp(ecom1->str, ecom2->str);
}
+/*
+ * Compare L3 Route Targets.
+ */
+static int evpn_vrf_route_target_cmp(struct vrf_route_target *rt1,
+ struct vrf_route_target *rt2)
+{
+ return bgp_evpn_route_target_cmp(rt1->ecom, rt2->ecom);
+}
+
void bgp_evpn_xxport_delete_ecomm(void *val)
{
struct ecommunity *ecomm = val;
@@ -356,11 +366,37 @@ void bgp_evpn_xxport_delete_ecomm(void *val)
}
/*
+ * Delete l3 Route Target.
+ */
+static void evpn_vrf_rt_del(void *val)
+{
+ struct vrf_route_target *l3rt = val;
+
+ ecommunity_free(&l3rt->ecom);
+
+ XFREE(MTYPE_VRF_ROUTE_TARGET, l3rt);
+}
+
+/*
+ * Allocate a new l3 Route Target.
+ */
+static struct vrf_route_target *evpn_vrf_rt_new(struct ecommunity *ecom)
+{
+ struct vrf_route_target *l3rt;
+
+ l3rt = XCALLOC(MTYPE_VRF_ROUTE_TARGET, sizeof(struct vrf_route_target));
+
+ l3rt->ecom = ecom;
+
+ return l3rt;
+}
+
+/*
* Mask off global-admin field of specified extended community (RT),
* just retain the local-admin field.
*/
static inline void mask_ecom_global_admin(struct ecommunity_val *dst,
- struct ecommunity_val *src)
+ const struct ecommunity_val *src)
{
uint8_t type;
@@ -376,33 +412,55 @@ static inline void mask_ecom_global_admin(struct ecommunity_val *dst,
}
/*
- * Map one RT to specified VRF.
- * bgp_vrf = BGP vrf instance
+ * Converts the RT to Ecommunity Value and adjusts masking based
+ * on flags set for RT.
*/
-static void map_vrf_to_rt(struct bgp *bgp_vrf, struct ecommunity_val *eval)
+static void vrf_rt2ecom_val(struct ecommunity_val *to_eval,
+ const struct vrf_route_target *l3rt, int iter)
{
- struct vrf_irt_node *irt = NULL;
- struct ecommunity_val eval_tmp;
+ const struct ecommunity_val *eval;
- /* If using "automatic" RT,
+ eval = (const struct ecommunity_val *)(l3rt->ecom->val +
+ (iter * ECOMMUNITY_SIZE));
+ /* If using "automatic" or "wildcard *" RT,
* we only care about the local-admin sub-field.
* This is to facilitate using L3VNI(VRF-VNI)
- * as the RT for EBGP peering too.
+ * as the RT for EBGP peering too and simplify
+ * configurations by allowing any ASN via '*'.
*/
- memcpy(&eval_tmp, eval, ECOMMUNITY_SIZE);
- if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD))
- mask_ecom_global_admin(&eval_tmp, eval);
+ memcpy(to_eval, eval, ECOMMUNITY_SIZE);
- irt = lookup_vrf_import_rt(&eval_tmp);
- if (irt && is_vrf_present_in_irt_vrfs(irt->vrfs, bgp_vrf))
- /* Already mapped. */
- return;
+ if (CHECK_FLAG(l3rt->flags, BGP_VRF_RT_AUTO) ||
+ CHECK_FLAG(l3rt->flags, BGP_VRF_RT_WILD))
+ mask_ecom_global_admin(to_eval, eval);
+}
- if (!irt)
- irt = vrf_import_rt_new(&eval_tmp);
+/*
+ * Map one RT to specified VRF.
+ * bgp_vrf = BGP vrf instance
+ */
+static void map_vrf_to_rt(struct bgp *bgp_vrf, struct vrf_route_target *l3rt)
+{
+ uint32_t i = 0;
+
+ for (i = 0; i < l3rt->ecom->size; i++) {
+ struct vrf_irt_node *irt = NULL;
+ struct ecommunity_val eval_tmp;
+
+ /* Adjust masking for value */
+ vrf_rt2ecom_val(&eval_tmp, l3rt, i);
+
+ irt = lookup_vrf_import_rt(&eval_tmp);
- /* Add VRF to the list for this RT. */
- listnode_add(irt->vrfs, bgp_vrf);
+ if (irt && is_vrf_present_in_irt_vrfs(irt->vrfs, bgp_vrf))
+ return; /* Already mapped. */
+
+ if (!irt)
+ irt = vrf_import_rt_new(&eval_tmp);
+
+ /* Add VRF to the list for this RT. */
+ listnode_add(irt->vrfs, bgp_vrf);
+ }
}
/*
@@ -410,12 +468,28 @@ static void map_vrf_to_rt(struct bgp *bgp_vrf, struct ecommunity_val *eval)
* VRFs for this RT, then the RT hash is deleted.
* bgp_vrf: BGP VRF specific instance
*/
-static void unmap_vrf_from_rt(struct bgp *bgp_vrf, struct vrf_irt_node *irt)
+static void unmap_vrf_from_rt(struct bgp *bgp_vrf,
+ struct vrf_route_target *l3rt)
{
- /* Delete VRF from list for this RT. */
- listnode_delete(irt->vrfs, bgp_vrf);
- if (!listnode_head(irt->vrfs)) {
- vrf_import_rt_free(irt);
+ uint32_t i;
+
+ for (i = 0; i < l3rt->ecom->size; i++) {
+ struct vrf_irt_node *irt;
+ struct ecommunity_val eval_tmp;
+
+ /* Adjust masking for value */
+ vrf_rt2ecom_val(&eval_tmp, l3rt, i);
+
+ irt = lookup_vrf_import_rt(&eval_tmp);
+
+ if (!irt)
+ return; /* Not mapped */
+
+ /* Delete VRF from list for this RT. */
+ listnode_delete(irt->vrfs, bgp_vrf);
+
+ if (!listnode_head(irt->vrfs))
+ vrf_import_rt_free(irt);
}
}
@@ -504,10 +578,14 @@ static void bgp_evpn_get_rmac_nexthop(struct bgpevpn *vpn,
* VNIs but the same across routers (in the same AS) for a particular
* VNI.
*/
-static void form_auto_rt(struct bgp *bgp, vni_t vni, struct list *rtl)
+static void form_auto_rt(struct bgp *bgp, vni_t vni, struct list *rtl,
+ bool is_l3)
{
struct ecommunity_val eval;
- struct ecommunity *ecomadd, *ecom;
+ struct ecommunity *ecomadd;
+ struct ecommunity *ecom;
+ struct vrf_route_target *l3rt;
+ struct vrf_route_target *newrt;
bool ecom_found = false;
struct listnode *node;
@@ -517,15 +595,30 @@ static void form_auto_rt(struct bgp *bgp, vni_t vni, struct list *rtl)
ecomadd = ecommunity_new();
ecommunity_add_val(ecomadd, &eval, false, false);
- for (ALL_LIST_ELEMENTS_RO(rtl, node, ecom))
- if (ecommunity_cmp(ecomadd, ecom)) {
- ecom_found = true;
- break;
- }
- if (!ecom_found)
- listnode_add_sort(rtl, ecomadd);
- else
+ if (is_l3) {
+ for (ALL_LIST_ELEMENTS_RO(rtl, node, l3rt))
+ if (ecommunity_cmp(ecomadd, l3rt->ecom)) {
+ ecom_found = true;
+ break;
+ }
+ } else {
+ for (ALL_LIST_ELEMENTS_RO(rtl, node, ecom))
+ if (ecommunity_cmp(ecomadd, ecom)) {
+ ecom_found = true;
+ break;
+ }
+ }
+
+ if (!ecom_found) {
+ if (is_l3) {
+ newrt = evpn_vrf_rt_new(ecomadd);
+ /* Label it as autoderived */
+ SET_FLAG(newrt->flags, BGP_VRF_RT_AUTO);
+ listnode_add_sort(rtl, newrt);
+ } else
+ listnode_add_sort(rtl, ecomadd);
+ } else
ecommunity_free(&ecomadd);
}
@@ -923,8 +1016,9 @@ static void build_evpn_type5_route_extcomm(struct bgp *bgp_vrf,
struct ecommunity_val eval_rmac;
bgp_encap_types tnl_type;
struct listnode *node, *nnode;
- struct ecommunity *ecom;
+ struct vrf_route_target *l3rt;
struct ecommunity *old_ecom;
+ struct ecommunity *ecom;
struct list *vrf_export_rtl = NULL;
/* Encap */
@@ -948,10 +1042,10 @@ static void build_evpn_type5_route_extcomm(struct bgp *bgp_vrf,
/* Add the export RTs for L3VNI/VRF */
vrf_export_rtl = bgp_vrf->vrf_export_rtl;
- for (ALL_LIST_ELEMENTS(vrf_export_rtl, node, nnode, ecom))
+ for (ALL_LIST_ELEMENTS(vrf_export_rtl, node, nnode, l3rt))
bgp_attr_set_ecommunity(
- attr,
- ecommunity_merge(bgp_attr_get_ecommunity(attr), ecom));
+ attr, ecommunity_merge(bgp_attr_get_ecommunity(attr),
+ l3rt->ecom));
/* add the router mac extended community */
if (!is_zero_mac(&attr->rmac)) {
@@ -988,6 +1082,7 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr,
bgp_encap_types tnl_type;
struct listnode *node, *nnode;
struct ecommunity *ecom;
+ struct vrf_route_target *l3rt;
uint32_t seqnum;
struct list *vrf_export_rtl = NULL;
@@ -1016,12 +1111,12 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr,
vrf_export_rtl = bgpevpn_get_vrf_export_rtl(vpn);
if (vrf_export_rtl && !list_isempty(vrf_export_rtl)) {
for (ALL_LIST_ELEMENTS(vrf_export_rtl, node, nnode,
- ecom))
+ l3rt))
bgp_attr_set_ecommunity(
attr,
ecommunity_merge(
bgp_attr_get_ecommunity(attr),
- ecom));
+ l3rt->ecom));
}
}
@@ -4758,13 +4853,14 @@ static void evpn_auto_rt_import_add_for_vrf(struct bgp *bgp_vrf)
{
struct bgp *bgp_evpn = NULL;
- form_auto_rt(bgp_vrf, bgp_vrf->l3vni, bgp_vrf->vrf_import_rtl);
- UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD);
+ form_auto_rt(bgp_vrf, bgp_vrf->l3vni, bgp_vrf->vrf_import_rtl, true);
/* Map RT to VRF */
bgp_evpn = bgp_get_evpn();
+
if (!bgp_evpn)
return;
+
bgp_evpn_map_vrf_to_its_rts(bgp_vrf);
}
@@ -4773,7 +4869,8 @@ static void evpn_auto_rt_import_add_for_vrf(struct bgp *bgp_vrf)
*/
static void evpn_auto_rt_import_delete_for_vrf(struct bgp *bgp_vrf)
{
- evpn_rt_delete_auto(bgp_vrf, bgp_vrf->l3vni, bgp_vrf->vrf_import_rtl);
+ evpn_rt_delete_auto(bgp_vrf, bgp_vrf->l3vni, bgp_vrf->vrf_import_rtl,
+ true);
}
/*
@@ -4781,8 +4878,7 @@ static void evpn_auto_rt_import_delete_for_vrf(struct bgp *bgp_vrf)
*/
static void evpn_auto_rt_export_add_for_vrf(struct bgp *bgp_vrf)
{
- UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_RT_CFGD);
- form_auto_rt(bgp_vrf, bgp_vrf->l3vni, bgp_vrf->vrf_export_rtl);
+ form_auto_rt(bgp_vrf, bgp_vrf->l3vni, bgp_vrf->vrf_export_rtl, true);
}
/*
@@ -4790,7 +4886,8 @@ static void evpn_auto_rt_export_add_for_vrf(struct bgp *bgp_vrf)
*/
static void evpn_auto_rt_export_delete_for_vrf(struct bgp *bgp_vrf)
{
- evpn_rt_delete_auto(bgp_vrf, bgp_vrf->l3vni, bgp_vrf->vrf_export_rtl);
+ evpn_rt_delete_auto(bgp_vrf, bgp_vrf->l3vni, bgp_vrf->vrf_export_rtl,
+ true);
}
static void bgp_evpn_handle_export_rt_change_for_vrf(struct bgp *bgp_vrf)
@@ -5033,36 +5130,65 @@ void bgp_evpn_advertise_type5_routes(struct bgp *bgp_vrf, afi_t afi,
}
}
-void evpn_rt_delete_auto(struct bgp *bgp, vni_t vni, struct list *rtl)
+static void rt_list_remove_node(struct list *rt_list,
+ struct ecommunity *ecomdel, bool is_l3)
{
- struct listnode *node, *nnode, *node_to_del;
- struct ecommunity *ecom, *ecom_auto;
+ struct listnode *node = NULL, *nnode = NULL, *node_to_del = NULL;
+ struct vrf_route_target *l3rt = NULL;
+ struct ecommunity *ecom = NULL;
+
+ if (is_l3) {
+ for (ALL_LIST_ELEMENTS(rt_list, node, nnode, l3rt)) {
+ if (ecommunity_match(l3rt->ecom, ecomdel)) {
+ evpn_vrf_rt_del(l3rt);
+ node_to_del = node;
+ break;
+ }
+ }
+ } else {
+ for (ALL_LIST_ELEMENTS(rt_list, node, nnode, ecom)) {
+ if (ecommunity_match(ecom, ecomdel)) {
+ ecommunity_free(&ecom);
+ node_to_del = node;
+ break;
+ }
+ }
+ }
+
+
+ if (node_to_del)
+ list_delete_node(rt_list, node_to_del);
+}
+
+void evpn_rt_delete_auto(struct bgp *bgp, vni_t vni, struct list *rtl,
+ bool is_l3)
+{
+ struct ecommunity *ecom_auto;
struct ecommunity_val eval;
if (bgp->advertise_autort_rfc8365)
vni |= EVPN_AUTORT_VXLAN;
+
encode_route_target_as((bgp->as & 0xFFFF), vni, &eval);
ecom_auto = ecommunity_new();
ecommunity_add_val(ecom_auto, &eval, false, false);
- node_to_del = NULL;
- for (ALL_LIST_ELEMENTS(rtl, node, nnode, ecom)) {
- if (ecommunity_match(ecom, ecom_auto)) {
- ecommunity_free(&ecom);
- node_to_del = node;
- break;
- }
- }
-
- if (node_to_del)
- list_delete_node(rtl, node_to_del);
+ rt_list_remove_node(rtl, ecom_auto, is_l3);
ecommunity_free(&ecom_auto);
}
-void bgp_evpn_configure_import_rt_for_vrf(struct bgp *bgp_vrf,
- struct ecommunity *ecomadd)
+static void evpn_vrf_rt_routes_map(struct bgp *bgp_vrf)
+{
+ /* map VRFs to its RTs and install routes matching this new RT */
+ if (is_l3vni_live(bgp_vrf)) {
+ bgp_evpn_map_vrf_to_its_rts(bgp_vrf);
+ install_routes_for_vrf(bgp_vrf);
+ }
+}
+
+static void evpn_vrf_rt_routes_unmap(struct bgp *bgp_vrf)
{
/* uninstall routes from vrf */
if (is_l3vni_live(bgp_vrf))
@@ -5070,112 +5196,189 @@ void bgp_evpn_configure_import_rt_for_vrf(struct bgp *bgp_vrf,
/* Cleanup the RT to VRF mapping */
bgp_evpn_unmap_vrf_from_its_rts(bgp_vrf);
+}
- /* Remove auto generated RT */
- evpn_auto_rt_import_delete_for_vrf(bgp_vrf);
+static bool rt_list_has_cfgd_rt(struct list *rt_list)
+{
+ struct listnode *node = NULL, *nnode = NULL;
+ struct vrf_route_target *l3rt = NULL;
+
+ for (ALL_LIST_ELEMENTS(rt_list, node, nnode, l3rt)) {
+ if (!CHECK_FLAG(l3rt->flags, BGP_VRF_RT_AUTO))
+ return true;
+ }
+
+ return false;
+}
+
+static void unconfigure_import_rt_for_vrf_fini(struct bgp *bgp_vrf)
+{
+ if (!bgp_vrf->vrf_import_rtl)
+ return; /* this should never fail */
+
+ if (!is_l3vni_live(bgp_vrf))
+ return; /* Nothing to do if no vni */
+
+ /* fall back to auto-generated RT if this was the last RT */
+ if (list_isempty(bgp_vrf->vrf_import_rtl))
+ evpn_auto_rt_import_add_for_vrf(bgp_vrf);
+}
+
+static void unconfigure_export_rt_for_vrf_fini(struct bgp *bgp_vrf)
+{
+
+ if (!bgp_vrf->vrf_export_rtl)
+ return; /* this should never fail */
+
+ if (!is_l3vni_live(bgp_vrf))
+ return; /* Nothing to do if no vni */
+
+ /* fall back to auto-generated RT if this was the last RT */
+ if (list_isempty(bgp_vrf->vrf_export_rtl))
+ evpn_auto_rt_export_add_for_vrf(bgp_vrf);
+
+ bgp_evpn_handle_export_rt_change_for_vrf(bgp_vrf);
+}
+
+void bgp_evpn_configure_import_rt_for_vrf(struct bgp *bgp_vrf,
+ struct ecommunity *ecomadd,
+ bool is_wildcard)
+{
+ struct vrf_route_target *newrt;
+
+ newrt = evpn_vrf_rt_new(ecomadd);
+
+ if (is_wildcard)
+ SET_FLAG(newrt->flags, BGP_VRF_RT_WILD);
+
+ evpn_vrf_rt_routes_unmap(bgp_vrf);
+
+ /* Remove auto generated RT if not configured */
+ if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_AUTO_RT_CFGD))
+ evpn_auto_rt_import_delete_for_vrf(bgp_vrf);
/* Add the newly configured RT to RT list */
- listnode_add_sort(bgp_vrf->vrf_import_rtl, ecomadd);
+ listnode_add_sort(bgp_vrf->vrf_import_rtl, newrt);
+
SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD);
- /* map VRF to its RTs and install routes matching the new RTs */
- if (is_l3vni_live(bgp_vrf)) {
- bgp_evpn_map_vrf_to_its_rts(bgp_vrf);
- install_routes_for_vrf(bgp_vrf);
- }
+ evpn_vrf_rt_routes_map(bgp_vrf);
+}
+
+void bgp_evpn_configure_import_auto_rt_for_vrf(struct bgp *bgp_vrf)
+{
+ if (CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_AUTO_RT_CFGD))
+ return; /* Already configured */
+
+ SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_AUTO_RT_CFGD);
+
+ if (!is_l3vni_live(bgp_vrf))
+ return; /* Wait for VNI before adding rts */
+
+ evpn_vrf_rt_routes_unmap(bgp_vrf);
+
+ evpn_auto_rt_import_add_for_vrf(bgp_vrf);
+
+ evpn_vrf_rt_routes_map(bgp_vrf);
}
void bgp_evpn_unconfigure_import_rt_for_vrf(struct bgp *bgp_vrf,
struct ecommunity *ecomdel)
{
- struct listnode *node = NULL, *nnode = NULL, *node_to_del = NULL;
- struct ecommunity *ecom = NULL;
+ if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD))
+ return; /* Already un-configured */
- /* uninstall routes from vrf */
- if (is_l3vni_live(bgp_vrf))
- uninstall_routes_for_vrf(bgp_vrf);
+ evpn_vrf_rt_routes_unmap(bgp_vrf);
- /* Cleanup the RT to VRF mapping */
- bgp_evpn_unmap_vrf_from_its_rts(bgp_vrf);
+ /* Remove rt */
+ rt_list_remove_node(bgp_vrf->vrf_import_rtl, ecomdel, true);
- /* remove the RT from the RT list */
- for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_import_rtl, node, nnode, ecom)) {
- if (ecommunity_match(ecom, ecomdel)) {
- ecommunity_free(&ecom);
- node_to_del = node;
- break;
- }
- }
+ if (!rt_list_has_cfgd_rt(bgp_vrf->vrf_import_rtl))
+ UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD);
- if (node_to_del)
- list_delete_node(bgp_vrf->vrf_import_rtl, node_to_del);
+ unconfigure_import_rt_for_vrf_fini(bgp_vrf);
- assert(bgp_vrf->vrf_import_rtl);
- /* fallback to auto import rt, if this was the last RT */
- if (bgp_vrf->vrf_import_rtl && list_isempty(bgp_vrf->vrf_import_rtl)) {
- UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD);
- if (is_l3vni_live(bgp_vrf))
- evpn_auto_rt_import_add_for_vrf(bgp_vrf);
- }
+ evpn_vrf_rt_routes_map(bgp_vrf);
+}
- /* map VRFs to its RTs and install routes matching this new RT */
- if (is_l3vni_live(bgp_vrf)) {
- bgp_evpn_map_vrf_to_its_rts(bgp_vrf);
- install_routes_for_vrf(bgp_vrf);
- }
+void bgp_evpn_unconfigure_import_auto_rt_for_vrf(struct bgp *bgp_vrf)
+{
+ if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_AUTO_RT_CFGD))
+ return; /* Already un-configured */
+
+ evpn_vrf_rt_routes_unmap(bgp_vrf);
+
+ /* remove auto-generated RT */
+ evpn_auto_rt_import_delete_for_vrf(bgp_vrf);
+
+ UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_AUTO_RT_CFGD);
+
+ unconfigure_import_rt_for_vrf_fini(bgp_vrf);
+
+ evpn_vrf_rt_routes_map(bgp_vrf);
}
void bgp_evpn_configure_export_rt_for_vrf(struct bgp *bgp_vrf,
struct ecommunity *ecomadd)
{
- /* remove auto-generated RT */
- evpn_auto_rt_export_delete_for_vrf(bgp_vrf);
+ struct vrf_route_target *newrt;
+
+ newrt = evpn_vrf_rt_new(ecomadd);
+
+ /* Remove auto generated RT if not configured */
+ if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_AUTO_RT_CFGD))
+ evpn_auto_rt_export_delete_for_vrf(bgp_vrf);
/* Add the new RT to the RT list */
- listnode_add_sort(bgp_vrf->vrf_export_rtl, ecomadd);
+ listnode_add_sort(bgp_vrf->vrf_export_rtl, newrt);
+
SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_RT_CFGD);
if (is_l3vni_live(bgp_vrf))
bgp_evpn_handle_export_rt_change_for_vrf(bgp_vrf);
}
+void bgp_evpn_configure_export_auto_rt_for_vrf(struct bgp *bgp_vrf)
+{
+ if (CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_AUTO_RT_CFGD))
+ return; /* Already configured */
+
+ SET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_AUTO_RT_CFGD);
+
+ if (!is_l3vni_live(bgp_vrf))
+ return; /* Wait for VNI before adding rts */
+
+ evpn_auto_rt_export_add_for_vrf(bgp_vrf);
+
+ bgp_evpn_handle_export_rt_change_for_vrf(bgp_vrf);
+}
+
void bgp_evpn_unconfigure_export_rt_for_vrf(struct bgp *bgp_vrf,
struct ecommunity *ecomdel)
{
- struct listnode *node = NULL, *nnode = NULL, *node_to_del = NULL;
- struct ecommunity *ecom = NULL;
+ if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_RT_CFGD))
+ return; /* Already un-configured */
- /* Remove the RT from the RT list */
- for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_export_rtl, node, nnode, ecom)) {
- if (ecommunity_match(ecom, ecomdel)) {
- ecommunity_free(&ecom);
- node_to_del = node;
- break;
- }
- }
+ /* Remove rt */
+ rt_list_remove_node(bgp_vrf->vrf_export_rtl, ecomdel, true);
- if (node_to_del)
- list_delete_node(bgp_vrf->vrf_export_rtl, node_to_del);
+ if (!rt_list_has_cfgd_rt(bgp_vrf->vrf_export_rtl))
+ UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_RT_CFGD);
- /*
- * Temporary assert to make SA happy.
- * The ALL_LIST_ELEMENTS macro above has a NULL check
- * which means that SA is going to complain about
- * the list_isempty call, which doesn't NULL check.
- * So until we get this situation cleaned up, here
- * we are.
- */
- assert(bgp_vrf->vrf_export_rtl);
+ unconfigure_export_rt_for_vrf_fini(bgp_vrf);
+}
- /* fall back to auto-generated RT if this was the last RT */
- if (list_isempty(bgp_vrf->vrf_export_rtl)) {
- UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_RT_CFGD);
- if (is_l3vni_live(bgp_vrf))
- evpn_auto_rt_export_add_for_vrf(bgp_vrf);
- }
+void bgp_evpn_unconfigure_export_auto_rt_for_vrf(struct bgp *bgp_vrf)
+{
+ if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_AUTO_RT_CFGD))
+ return; /* Already un-configured */
- if (is_l3vni_live(bgp_vrf))
- bgp_evpn_handle_export_rt_change_for_vrf(bgp_vrf);
+ /* remove auto-generated RT */
+ evpn_auto_rt_export_delete_for_vrf(bgp_vrf);
+
+ UNSET_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_AUTO_RT_CFGD);
+
+ unconfigure_export_rt_for_vrf_fini(bgp_vrf);
}
/*
@@ -5604,19 +5807,11 @@ int bgp_nlri_parse_evpn(struct peer *peer, struct attr *attr,
*/
void bgp_evpn_map_vrf_to_its_rts(struct bgp *bgp_vrf)
{
- uint32_t i = 0;
- struct ecommunity_val *eval = NULL;
- struct listnode *node = NULL, *nnode = NULL;
- struct ecommunity *ecom = NULL;
+ struct listnode *node, *nnode;
+ struct vrf_route_target *l3rt;
- for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_import_rtl, node, nnode, ecom)) {
- for (i = 0; i < ecom->size; i++) {
- eval = (struct ecommunity_val *)(ecom->val
- + (i
- * ECOMMUNITY_SIZE));
- map_vrf_to_rt(bgp_vrf, eval);
- }
- }
+ for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_import_rtl, node, nnode, l3rt))
+ map_vrf_to_rt(bgp_vrf, l3rt);
}
/*
@@ -5624,37 +5819,13 @@ void bgp_evpn_map_vrf_to_its_rts(struct bgp *bgp_vrf)
*/
void bgp_evpn_unmap_vrf_from_its_rts(struct bgp *bgp_vrf)
{
- uint32_t i;
- struct ecommunity_val *eval;
struct listnode *node, *nnode;
- struct ecommunity *ecom;
-
- for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_import_rtl, node, nnode, ecom)) {
- for (i = 0; i < ecom->size; i++) {
- struct vrf_irt_node *irt;
- struct ecommunity_val eval_tmp;
-
- eval = (struct ecommunity_val *)(ecom->val
- + (i
- * ECOMMUNITY_SIZE));
- /* If using "automatic" RT, we only care about the
- * local-admin sub-field.
- * This is to facilitate using VNI as the RT for EBGP
- * peering too.
- */
- memcpy(&eval_tmp, eval, ECOMMUNITY_SIZE);
- if (!CHECK_FLAG(bgp_vrf->vrf_flags,
- BGP_VRF_IMPORT_RT_CFGD))
- mask_ecom_global_admin(&eval_tmp, eval);
+ struct vrf_route_target *l3rt;
- irt = lookup_vrf_import_rt(&eval_tmp);
- if (irt)
- unmap_vrf_from_rt(bgp_vrf, irt);
- }
- }
+ for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_import_rtl, node, nnode, l3rt))
+ unmap_vrf_from_rt(bgp_vrf, l3rt);
}
-
/*
* Map the RTs (configured or automatically derived) of a VNI to the VNI.
* The mapping will be used during route processing.
@@ -5716,7 +5887,7 @@ void bgp_evpn_unmap_vni_from_its_rts(struct bgp *bgp, struct bgpevpn *vpn)
*/
void bgp_evpn_derive_auto_rt_import(struct bgp *bgp, struct bgpevpn *vpn)
{
- form_auto_rt(bgp, vpn->vni, vpn->import_rtl);
+ form_auto_rt(bgp, vpn->vni, vpn->import_rtl, false);
UNSET_FLAG(vpn->flags, VNI_FLAG_IMPRT_CFGD);
/* Map RT to VNI */
@@ -5728,7 +5899,7 @@ void bgp_evpn_derive_auto_rt_import(struct bgp *bgp, struct bgpevpn *vpn)
*/
void bgp_evpn_derive_auto_rt_export(struct bgp *bgp, struct bgpevpn *vpn)
{
- form_auto_rt(bgp, vpn->vni, vpn->export_rtl);
+ form_auto_rt(bgp, vpn->vni, vpn->export_rtl, false);
UNSET_FLAG(vpn->flags, VNI_FLAG_EXPRT_CFGD);
}
@@ -6140,12 +6311,14 @@ int bgp_evpn_local_l3vni_add(vni_t l3vni, vrf_id_t vrf_id,
}
/* Map auto derive or configured RTs */
- if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD))
+ if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_RT_CFGD) ||
+ CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_IMPORT_AUTO_RT_CFGD))
evpn_auto_rt_import_add_for_vrf(bgp_vrf);
else
bgp_evpn_map_vrf_to_its_rts(bgp_vrf);
- if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_RT_CFGD))
+ if (!CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_RT_CFGD) ||
+ CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_EXPORT_AUTO_RT_CFGD))
evpn_auto_rt_export_add_for_vrf(bgp_vrf);
/* auto derive RD */
@@ -6518,12 +6691,12 @@ void bgp_evpn_init(struct bgp *bgp)
"BGP VRF Import RT Hash");
bgp->vrf_import_rtl = list_new();
bgp->vrf_import_rtl->cmp =
- (int (*)(void *, void *))bgp_evpn_route_target_cmp;
- bgp->vrf_import_rtl->del = bgp_evpn_xxport_delete_ecomm;
+ (int (*)(void *, void *))evpn_vrf_route_target_cmp;
+ bgp->vrf_import_rtl->del = evpn_vrf_rt_del;
bgp->vrf_export_rtl = list_new();
bgp->vrf_export_rtl->cmp =
- (int (*)(void *, void *))bgp_evpn_route_target_cmp;
- bgp->vrf_export_rtl->del = bgp_evpn_xxport_delete_ecomm;
+ (int (*)(void *, void *))evpn_vrf_route_target_cmp;
+ bgp->vrf_export_rtl->del = evpn_vrf_rt_del;
bgp->l2vnis = list_new();
bgp->l2vnis->cmp = vni_list_cmp;
/* By default Duplicate Address Dection is enabled.
diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h
index eb78a755d..3f18e4e9f 100644
--- a/bgpd/bgp_evpn_private.h
+++ b/bgpd/bgp_evpn_private.h
@@ -195,6 +195,18 @@ struct evpn_remote_ip {
struct list *macip_path_list;
};
+/*
+ * Wrapper struct for l3 RT's
+ */
+struct vrf_route_target {
+ /* flags based on config to determine how RTs are handled */
+ uint8_t flags;
+#define BGP_VRF_RT_AUTO (1 << 0)
+#define BGP_VRF_RT_WILD (1 << 1)
+
+ struct ecommunity *ecom;
+};
+
static inline int is_vrf_rd_configured(struct bgp *bgp_vrf)
{
return (CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_RD_CFGD));
@@ -662,15 +674,21 @@ extern struct zclient *zclient;
extern void bgp_evpn_install_uninstall_default_route(struct bgp *bgp_vrf,
afi_t afi, safi_t safi,
bool add);
-extern void evpn_rt_delete_auto(struct bgp *, vni_t, struct list *);
+extern void evpn_rt_delete_auto(struct bgp *bgp, vni_t vni, struct list *rtl,
+ bool is_l3);
extern void bgp_evpn_configure_export_rt_for_vrf(struct bgp *bgp_vrf,
struct ecommunity *ecomadd);
+extern void bgp_evpn_configure_export_auto_rt_for_vrf(struct bgp *bgp_vrf);
extern void bgp_evpn_unconfigure_export_rt_for_vrf(struct bgp *bgp_vrf,
struct ecommunity *ecomdel);
+extern void bgp_evpn_unconfigure_export_auto_rt_for_vrf(struct bgp *bgp_vrf);
extern void bgp_evpn_configure_import_rt_for_vrf(struct bgp *bgp_vrf,
- struct ecommunity *ecomadd);
+ struct ecommunity *ecomadd,
+ bool is_wildcard);
+extern void bgp_evpn_configure_import_auto_rt_for_vrf(struct bgp *bgp_vrf);
extern void bgp_evpn_unconfigure_import_rt_for_vrf(struct bgp *bgp_vrf,
struct ecommunity *ecomdel);
+extern void bgp_evpn_unconfigure_import_auto_rt_for_vrf(struct bgp *bgp_vrf);
extern int bgp_evpn_handle_export_rt_change(struct bgp *bgp,
struct bgpevpn *vpn);
extern void bgp_evpn_handle_autort_change(struct bgp *bgp);
diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c
index 12fe65c72..88c1329f4 100644
--- a/bgpd/bgp_evpn_vty.c
+++ b/bgpd/bgp_evpn_vty.c
@@ -375,7 +375,7 @@ static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf,
char buf1[INET6_ADDRSTRLEN];
char *ecom_str;
struct listnode *node, *nnode;
- struct ecommunity *ecom;
+ struct vrf_route_target *l3rt;
json_object *json_import_rtl = NULL;
json_object *json_export_rtl = NULL;
char buf2[ETHER_ADDR_STRLEN];
@@ -433,8 +433,8 @@ static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf,
if (!json)
vty_out(vty, " Import Route Target:\n");
- for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_import_rtl, node, nnode, ecom)) {
- ecom_str = ecommunity_ecom2str(ecom,
+ for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_import_rtl, node, nnode, l3rt)) {
+ ecom_str = ecommunity_ecom2str(l3rt->ecom,
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
if (json)
@@ -451,8 +451,8 @@ static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf,
else
vty_out(vty, " Export Route Target:\n");
- for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_export_rtl, node, nnode, ecom)) {
- ecom_str = ecommunity_ecom2str(ecom,
+ for (ALL_LIST_ELEMENTS(bgp_vrf->vrf_export_rtl, node, nnode, l3rt)) {
+ ecom_str = ecommunity_ecom2str(l3rt->ecom,
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
if (json)
@@ -985,7 +985,7 @@ static void show_l3vni_entry(struct vty *vty, struct bgp *bgp,
char rt_buf[25];
char *ecom_str;
struct listnode *node, *nnode;
- struct ecommunity *ecom;
+ struct vrf_route_target *l3rt;
if (!bgp->l3vni)
return;
@@ -1026,8 +1026,8 @@ static void show_l3vni_entry(struct vty *vty, struct bgp *bgp,
&bgp->vrf_prd);
}
- for (ALL_LIST_ELEMENTS(bgp->vrf_import_rtl, node, nnode, ecom)) {
- ecom_str = ecommunity_ecom2str(ecom,
+ for (ALL_LIST_ELEMENTS(bgp->vrf_import_rtl, node, nnode, l3rt)) {
+ ecom_str = ecommunity_ecom2str(l3rt->ecom,
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
if (json) {
@@ -1054,8 +1054,8 @@ static void show_l3vni_entry(struct vty *vty, struct bgp *bgp,
if (json)
json_object_object_add(json_vni, "importRTs", json_import_rtl);
- for (ALL_LIST_ELEMENTS(bgp->vrf_export_rtl, node, nnode, ecom)) {
- ecom_str = ecommunity_ecom2str(ecom,
+ for (ALL_LIST_ELEMENTS(bgp->vrf_export_rtl, node, nnode, l3rt)) {
+ ecom_str = ecommunity_ecom2str(l3rt->ecom,
ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
if (json) {
@@ -2056,12 +2056,12 @@ DEFUN(no_evpnrt5_network,
static void evpn_import_rt_delete_auto(struct bgp *bgp, struct bgpevpn *vpn)
{
- evpn_rt_delete_auto(bgp, vpn->vni, vpn->import_rtl);
+ evpn_rt_delete_auto(bgp, vpn->vni, vpn->import_rtl, false);
}
static void evpn_export_rt_delete_auto(struct bgp *bgp, struct bgpevpn *vpn)
{
- evpn_rt_delete_auto(bgp, vpn->vni, vpn->export_rtl);
+ evpn_rt_delete_auto(bgp, vpn->vni, vpn->export_rtl, false);
}
/*
@@ -3495,9 +3495,7 @@ static void write_vni_config(struct vty *vty, struct bgpevpn *vpn)
}
}
-#ifndef VTYSH_EXTRACT_PL
#include "bgpd/bgp_evpn_vty_clippy.c"
-#endif
DEFPY(bgp_evpn_flood_control,
bgp_evpn_flood_control_cmd,
@@ -4139,11 +4137,13 @@ DEFUN (bgp_evpn_advertise_type5,
DEFUN (no_bgp_evpn_advertise_type5,
no_bgp_evpn_advertise_type5_cmd,
- "no advertise " BGP_AFI_CMD_STR "" BGP_SAFI_CMD_STR,
+ "no advertise " BGP_AFI_CMD_STR "" BGP_SAFI_CMD_STR " [route-map WORD]",
NO_STR
"Advertise prefix routes\n"
BGP_AFI_HELP_STR
- BGP_SAFI_HELP_STR)
+ BGP_SAFI_HELP_STR
+ "route-map for filtering specific routes\n"
+ "Name of the route map\n")
{
struct bgp *bgp_vrf = VTY_GET_CONTEXT(bgp); /* bgp vrf instance */
int idx_afi = 0;
@@ -6274,18 +6274,35 @@ DEFUN (no_bgp_evpn_vni_rd_without_val,
* Loop over all extended-communities in the route-target list rtl and
* return 1 if we find ecomtarget
*/
-static int bgp_evpn_rt_matches_existing(struct list *rtl,
- struct ecommunity *ecomtarget)
+static bool bgp_evpn_rt_matches_existing(struct list *rtl,
+ struct ecommunity *ecomtarget)
{
- struct listnode *node, *nnode;
+ struct listnode *node;
struct ecommunity *ecom;
- for (ALL_LIST_ELEMENTS(rtl, node, nnode, ecom)) {
+ for (ALL_LIST_ELEMENTS_RO(rtl, node, ecom)) {
if (ecommunity_match(ecom, ecomtarget))
- return 1;
+ return true;
}
- return 0;
+ return false;
+}
+
+/*
+ * L3 RT version of above.
+ */
+static bool bgp_evpn_vrf_rt_matches_existing(struct list *rtl,
+ struct ecommunity *ecomtarget)
+{
+ struct listnode *node;
+ struct vrf_route_target *l3rt;
+
+ for (ALL_LIST_ELEMENTS_RO(rtl, node, l3rt)) {
+ if (ecommunity_match(l3rt->ecom, ecomtarget))
+ return true;
+ }
+
+ return false;
}
/* display L3VNI related info for a VRF instance */
@@ -6305,7 +6322,7 @@ DEFUN (show_bgp_vrf_l3vni_info,
struct bgp *bgp = NULL;
struct listnode *node = NULL;
struct bgpevpn *vpn = NULL;
- struct ecommunity *ecom = NULL;
+ struct vrf_route_target *l3rt;
json_object *json = NULL;
json_object *json_vnis = NULL;
json_object *json_export_rts = NULL;
@@ -6355,13 +6372,13 @@ DEFUN (show_bgp_vrf_l3vni_info,
vty_out(vty, "\n");
vty_out(vty, " Export-RTs:\n");
vty_out(vty, " ");
- for (ALL_LIST_ELEMENTS_RO(bgp->vrf_export_rtl, node, ecom))
- vty_out(vty, "%s ", ecommunity_str(ecom));
+ for (ALL_LIST_ELEMENTS_RO(bgp->vrf_export_rtl, node, l3rt))
+ vty_out(vty, "%s ", ecommunity_str(l3rt->ecom));
vty_out(vty, "\n");
vty_out(vty, " Import-RTs:\n");
vty_out(vty, " ");
- for (ALL_LIST_ELEMENTS_RO(bgp->vrf_import_rtl, node, ecom))
- vty_out(vty, "%s ", ecommunity_str(ecom));
+ for (ALL_LIST_ELEMENTS_RO(bgp->vrf_import_rtl, node, l3rt))
+ vty_out(vty, "%s ", ecommunity_str(l3rt->ecom));
vty_out(vty, "\n");
vty_out(vty, " RD: %pRD\n", &bgp->vrf_prd);
} else {
@@ -6385,17 +6402,19 @@ DEFUN (show_bgp_vrf_l3vni_info,
json_object_object_add(json, "l2vnis", json_vnis);
/* export rts */
- for (ALL_LIST_ELEMENTS_RO(bgp->vrf_export_rtl, node, ecom))
+ for (ALL_LIST_ELEMENTS_RO(bgp->vrf_export_rtl, node, l3rt))
json_object_array_add(
json_export_rts,
- json_object_new_string(ecommunity_str(ecom)));
+ json_object_new_string(
+ ecommunity_str(l3rt->ecom)));
json_object_object_add(json, "export-rts", json_export_rts);
/* import rts */
- for (ALL_LIST_ELEMENTS_RO(bgp->vrf_import_rtl, node, ecom))
+ for (ALL_LIST_ELEMENTS_RO(bgp->vrf_import_rtl, node, l3rt))
json_object_array_add(
json_import_rts,
- json_object_new_string(ecommunity_str(ecom)));
+ json_object_new_string(
+ ecommunity_str(l3rt->ecom)));
json_object_object_add(json, "import-rts", json_import_rts);
json_object_string_addf(json, "rd", "%pRD", &bgp->vrf_prd);
}
@@ -6405,22 +6424,126 @@ DEFUN (show_bgp_vrf_l3vni_info,
return CMD_SUCCESS;
}
+static int add_rt(struct bgp *bgp, struct ecommunity *ecom, bool is_import,
+ bool is_wildcard)
+{
+ /* Do nothing if we already have this route-target */
+ if (is_import) {
+ if (!bgp_evpn_vrf_rt_matches_existing(bgp->vrf_import_rtl,
+ ecom))
+ bgp_evpn_configure_import_rt_for_vrf(bgp, ecom,
+ is_wildcard);
+ else
+ return -1;
+ } else {
+ if (!bgp_evpn_vrf_rt_matches_existing(bgp->vrf_export_rtl,
+ ecom))
+ bgp_evpn_configure_export_rt_for_vrf(bgp, ecom);
+ else
+ return -1;
+ }
+
+ return 0;
+}
+
+static int del_rt(struct bgp *bgp, struct ecommunity *ecom, bool is_import)
+{
+ /* Verify we already have this route-target */
+ if (is_import) {
+ if (!bgp_evpn_vrf_rt_matches_existing(bgp->vrf_import_rtl,
+ ecom))
+ return -1;
+
+ bgp_evpn_unconfigure_import_rt_for_vrf(bgp, ecom);
+ } else {
+ if (!bgp_evpn_vrf_rt_matches_existing(bgp->vrf_export_rtl,
+ ecom))
+ return -1;
+
+ bgp_evpn_unconfigure_export_rt_for_vrf(bgp, ecom);
+ }
+
+ return 0;
+}
+
+static int parse_rtlist(struct bgp *bgp, struct vty *vty, int argc,
+ struct cmd_token **argv, int rt_idx, bool is_add,
+ bool is_import)
+{
+ int ret = CMD_SUCCESS;
+ bool is_wildcard = false;
+ struct ecommunity *ecom = NULL;
+
+ for (int i = rt_idx; i < argc; i++) {
+ is_wildcard = false;
+
+ /*
+ * Special handling for wildcard '*' here.
+ *
+ * Let's just convert it to 0 here so we dont have to modify
+ * the ecommunity parser.
+ */
+ if ((argv[i]->arg)[0] == '*') {
+ (argv[i]->arg)[0] = '0';
+ is_wildcard = true;
+ }
+
+ ecom = ecommunity_str2com(argv[i]->arg, ECOMMUNITY_ROUTE_TARGET,
+ 0);
+
+ /* Put it back as was */
+ if (is_wildcard)
+ (argv[i]->arg)[0] = '*';
+
+ if (!ecom) {
+ vty_out(vty, "%% Malformed Route Target list\n");
+ ret = CMD_WARNING;
+ continue;
+ }
+
+ ecommunity_str(ecom);
+
+ if (is_add) {
+ if (add_rt(bgp, ecom, is_import, is_wildcard) != 0) {
+ vty_out(vty,
+ "%% RT specified already configured for this VRF: %s\n",
+ argv[i]->arg);
+ ecommunity_free(&ecom);
+ ret = CMD_WARNING;
+ }
+
+ } else {
+ if (del_rt(bgp, ecom, is_import) != 0) {
+ vty_out(vty,
+ "%% RT specified does not match configuration for this VRF: %s\n",
+ argv[i]->arg);
+ ret = CMD_WARNING;
+ }
+
+ ecommunity_free(&ecom);
+ }
+ }
+
+ return ret;
+}
+
/* import/export rt for l3vni-vrf */
DEFUN (bgp_evpn_vrf_rt,
bgp_evpn_vrf_rt_cmd,
- "route-target <both|import|export> RT",
+ "route-target <both|import|export> RTLIST...",
"Route Target\n"
"import and export\n"
"import\n"
"export\n"
- "Route target (A.B.C.D:MN|EF:OPQR|GHJK:MN)\n")
+ "Space separated route target list (A.B.C.D:MN|EF:OPQR|GHJK:MN|*:OPQR|*:MN)\n")
{
+ int ret = CMD_SUCCESS;
+ int tmp_ret = CMD_SUCCESS;
int rt_type;
struct bgp *bgp = VTY_GET_CONTEXT(bgp);
- struct ecommunity *ecomadd = NULL;
if (!bgp)
- return CMD_WARNING;
+ return CMD_WARNING_CONFIG_FAILED;
if (!strcmp(argv[1]->arg, "import"))
rt_type = RT_TYPE_IMPORT;
@@ -6430,49 +6553,92 @@ DEFUN (bgp_evpn_vrf_rt,
rt_type = RT_TYPE_BOTH;
else {
vty_out(vty, "%% Invalid Route Target type\n");
- return CMD_WARNING;
+ return CMD_WARNING_CONFIG_FAILED;
}
- ecomadd = ecommunity_str2com(argv[2]->arg, ECOMMUNITY_ROUTE_TARGET, 0);
- if (!ecomadd) {
- vty_out(vty, "%% Malformed Route Target list\n");
- return CMD_WARNING;
+ if (strmatch(argv[2]->arg, "auto")) {
+ vty_out(vty, "%% `auto` cannot be configured via list\n");
+ return CMD_WARNING_CONFIG_FAILED;
}
- ecommunity_str(ecomadd);
- /* Add/update the import route-target */
- if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_IMPORT) {
- /* Do nothing if we already have this import route-target */
- if (!bgp_evpn_rt_matches_existing(bgp->vrf_import_rtl, ecomadd))
- bgp_evpn_configure_import_rt_for_vrf(bgp, ecomadd);
+ if (rt_type != RT_TYPE_IMPORT) {
+ for (int i = 2; i < argc; i++) {
+ if ((argv[i]->arg)[0] == '*') {
+ vty_out(vty,
+ "%% Wildcard '*' only applicable for import\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ }
}
- /* Add/update the export route-target */
- if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_EXPORT) {
- /* Do nothing if we already have this export route-target */
- if (!bgp_evpn_rt_matches_existing(bgp->vrf_export_rtl, ecomadd))
- bgp_evpn_configure_export_rt_for_vrf(bgp, ecomadd);
+ /* Add/update the import route-target */
+ if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_IMPORT)
+ tmp_ret = parse_rtlist(bgp, vty, argc, argv, 2, true, true);
+
+ if (ret == CMD_SUCCESS && tmp_ret != CMD_SUCCESS)
+ ret = tmp_ret;
+
+ if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_EXPORT)
+ tmp_ret = parse_rtlist(bgp, vty, argc, argv, 2, true, false);
+
+ if (ret == CMD_SUCCESS && tmp_ret != CMD_SUCCESS)
+ ret = tmp_ret;
+
+ return ret;
+}
+
+DEFPY (bgp_evpn_vrf_rt_auto,
+ bgp_evpn_vrf_rt_auto_cmd,
+ "route-target <both|import|export>$type auto",
+ "Route Target\n"
+ "import and export\n"
+ "import\n"
+ "export\n"
+ "Automatically derive route target\n")
+{
+ struct bgp *bgp = VTY_GET_CONTEXT(bgp);
+ int rt_type;
+
+ if (!bgp)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ if (strmatch(type, "import"))
+ rt_type = RT_TYPE_IMPORT;
+ else if (strmatch(type, "export"))
+ rt_type = RT_TYPE_EXPORT;
+ else if (strmatch(type, "both"))
+ rt_type = RT_TYPE_BOTH;
+ else {
+ vty_out(vty, "%% Invalid Route Target type\n");
+ return CMD_WARNING_CONFIG_FAILED;
}
+ if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_IMPORT)
+ bgp_evpn_configure_import_auto_rt_for_vrf(bgp);
+
+ if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_EXPORT)
+ bgp_evpn_configure_export_auto_rt_for_vrf(bgp);
+
return CMD_SUCCESS;
}
DEFUN (no_bgp_evpn_vrf_rt,
no_bgp_evpn_vrf_rt_cmd,
- "no route-target <both|import|export> RT",
+ "no route-target <both|import|export> RTLIST...",
NO_STR
"Route Target\n"
"import and export\n"
"import\n"
"export\n"
- EVPN_ASN_IP_HELP_STR)
+ "Space separated route target list (A.B.C.D:MN|EF:OPQR|GHJK:MN)\n")
{
struct bgp *bgp = VTY_GET_CONTEXT(bgp);
- int rt_type, found_ecomdel;
- struct ecommunity *ecomdel = NULL;
+ int ret = CMD_SUCCESS;
+ int tmp_ret = CMD_SUCCESS;
+ int rt_type;
if (!bgp)
- return CMD_WARNING;
+ return CMD_WARNING_CONFIG_FAILED;
if (!strcmp(argv[2]->arg, "import"))
rt_type = RT_TYPE_IMPORT;
@@ -6482,79 +6648,114 @@ DEFUN (no_bgp_evpn_vrf_rt,
rt_type = RT_TYPE_BOTH;
else {
vty_out(vty, "%% Invalid Route Target type\n");
- return CMD_WARNING;
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ if (!strcmp(argv[3]->arg, "auto")) {
+ vty_out(vty, "%% `auto` cannot be unconfigured via list\n");
+ return CMD_WARNING_CONFIG_FAILED;
}
if (rt_type == RT_TYPE_IMPORT) {
if (!CHECK_FLAG(bgp->vrf_flags, BGP_VRF_IMPORT_RT_CFGD)) {
vty_out(vty,
"%% Import RT is not configured for this VRF\n");
- return CMD_WARNING;
+ return CMD_WARNING_CONFIG_FAILED;
}
} else if (rt_type == RT_TYPE_EXPORT) {
if (!CHECK_FLAG(bgp->vrf_flags, BGP_VRF_EXPORT_RT_CFGD)) {
vty_out(vty,
"%% Export RT is not configured for this VRF\n");
- return CMD_WARNING;
+ return CMD_WARNING_CONFIG_FAILED;
}
} else if (rt_type == RT_TYPE_BOTH) {
if (!CHECK_FLAG(bgp->vrf_flags, BGP_VRF_IMPORT_RT_CFGD)
&& !CHECK_FLAG(bgp->vrf_flags, BGP_VRF_EXPORT_RT_CFGD)) {
vty_out(vty,
"%% Import/Export RT is not configured for this VRF\n");
- return CMD_WARNING;
+ return CMD_WARNING_CONFIG_FAILED;
}
}
- ecomdel = ecommunity_str2com(argv[3]->arg, ECOMMUNITY_ROUTE_TARGET, 0);
- if (!ecomdel) {
- vty_out(vty, "%% Malformed Route Target list\n");
- return CMD_WARNING;
+ if (rt_type != RT_TYPE_IMPORT) {
+ for (int i = 3; i < argc; i++) {
+ if ((argv[i]->arg)[0] == '*') {
+ vty_out(vty,
+ "%% Wildcard '*' only applicable for import\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ }
+ }
+
+ if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_IMPORT)
+ tmp_ret = parse_rtlist(bgp, vty, argc, argv, 3, false, true);
+
+ if (ret == CMD_SUCCESS && tmp_ret != CMD_SUCCESS)
+ ret = tmp_ret;
+
+ if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_EXPORT)
+ tmp_ret = parse_rtlist(bgp, vty, argc, argv, 3, false, false);
+
+ if (ret == CMD_SUCCESS && tmp_ret != CMD_SUCCESS)
+ ret = tmp_ret;
+
+ return ret;
+}
+
+DEFPY (no_bgp_evpn_vrf_rt_auto,
+ no_bgp_evpn_vrf_rt_auto_cmd,
+ "no route-target <both|import|export>$type auto",
+ NO_STR
+ "Route Target\n"
+ "import and export\n"
+ "import\n"
+ "export\n"
+ "Automatically derive route target\n")
+{
+ struct bgp *bgp = VTY_GET_CONTEXT(bgp);
+ int rt_type;
+
+ if (!bgp)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ if (strmatch(type, "import"))
+ rt_type = RT_TYPE_IMPORT;
+ else if (strmatch(type, "export"))
+ rt_type = RT_TYPE_EXPORT;
+ else if (strmatch(type, "both"))
+ rt_type = RT_TYPE_BOTH;
+ else {
+ vty_out(vty, "%% Invalid Route Target type\n");
+ return CMD_WARNING_CONFIG_FAILED;
}
- ecommunity_str(ecomdel);
if (rt_type == RT_TYPE_IMPORT) {
- if (!bgp_evpn_rt_matches_existing(bgp->vrf_import_rtl,
- ecomdel)) {
- ecommunity_free(&ecomdel);
+ if (!CHECK_FLAG(bgp->vrf_flags, BGP_VRF_IMPORT_AUTO_RT_CFGD)) {
vty_out(vty,
- "%% RT specified does not match configuration for this VRF\n");
- return CMD_WARNING;
+ "%% Import AUTO RT is not configured for this VRF\n");
+ return CMD_WARNING_CONFIG_FAILED;
}
- bgp_evpn_unconfigure_import_rt_for_vrf(bgp, ecomdel);
} else if (rt_type == RT_TYPE_EXPORT) {
- if (!bgp_evpn_rt_matches_existing(bgp->vrf_export_rtl,
- ecomdel)) {
- ecommunity_free(&ecomdel);
+ if (!CHECK_FLAG(bgp->vrf_flags, BGP_VRF_EXPORT_AUTO_RT_CFGD)) {
vty_out(vty,
- "%% RT specified does not match configuration for this VRF\n");
- return CMD_WARNING;
+ "%% Export AUTO RT is not configured for this VRF\n");
+ return CMD_WARNING_CONFIG_FAILED;
}
- bgp_evpn_unconfigure_export_rt_for_vrf(bgp, ecomdel);
} else if (rt_type == RT_TYPE_BOTH) {
- found_ecomdel = 0;
-
- if (bgp_evpn_rt_matches_existing(bgp->vrf_import_rtl,
- ecomdel)) {
- bgp_evpn_unconfigure_import_rt_for_vrf(bgp, ecomdel);
- found_ecomdel = 1;
- }
-
- if (bgp_evpn_rt_matches_existing(bgp->vrf_export_rtl,
- ecomdel)) {
- bgp_evpn_unconfigure_export_rt_for_vrf(bgp, ecomdel);
- found_ecomdel = 1;
- }
-
- if (!found_ecomdel) {
- ecommunity_free(&ecomdel);
+ if (!CHECK_FLAG(bgp->vrf_flags, BGP_VRF_IMPORT_AUTO_RT_CFGD) &&
+ !CHECK_FLAG(bgp->vrf_flags, BGP_VRF_EXPORT_AUTO_RT_CFGD)) {
vty_out(vty,
- "%% RT specified does not match configuration for this VRF\n");
- return CMD_WARNING;
+ "%% Import/Export AUTO RT is not configured for this VRF\n");
+ return CMD_WARNING_CONFIG_FAILED;
}
}
- ecommunity_free(&ecomdel);
+ if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_IMPORT)
+ bgp_evpn_unconfigure_import_auto_rt_for_vrf(bgp);
+
+ if (rt_type == RT_TYPE_BOTH || rt_type == RT_TYPE_EXPORT)
+ bgp_evpn_unconfigure_export_auto_rt_for_vrf(bgp);
+
return CMD_SUCCESS;
}
@@ -7041,31 +7242,66 @@ void bgp_config_write_evpn_info(struct vty *vty, struct bgp *bgp, afi_t afi,
if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_IMPORT_RT_CFGD)) {
char *ecom_str;
struct listnode *node, *nnode;
- struct ecommunity *ecom;
+ struct vrf_route_target *l3rt;
for (ALL_LIST_ELEMENTS(bgp->vrf_import_rtl, node, nnode,
- ecom)) {
+ l3rt)) {
+
+ if (CHECK_FLAG(l3rt->flags, BGP_VRF_RT_AUTO))
+ continue;
+
ecom_str = ecommunity_ecom2str(
- ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
- vty_out(vty, " route-target import %s\n", ecom_str);
+ l3rt->ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
+
+ if (CHECK_FLAG(l3rt->flags, BGP_VRF_RT_WILD)) {
+ char *vni_str = NULL;
+
+ vni_str = strchr(ecom_str, ':');
+ if (!vni_str) {
+ XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
+ continue;
+ }
+
+ /* Move pointer to vni */
+ vni_str += 1;
+
+ vty_out(vty, " route-target import *:%s\n",
+ vni_str);
+
+ } else
+ vty_out(vty, " route-target import %s\n",
+ ecom_str);
+
XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
}
}
+ /* import route-target auto */
+ if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_IMPORT_AUTO_RT_CFGD))
+ vty_out(vty, " route-target import auto\n");
+
/* export route-target */
if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_EXPORT_RT_CFGD)) {
char *ecom_str;
struct listnode *node, *nnode;
- struct ecommunity *ecom;
+ struct vrf_route_target *l3rt;
for (ALL_LIST_ELEMENTS(bgp->vrf_export_rtl, node, nnode,
- ecom)) {
+ l3rt)) {
+
+ if (CHECK_FLAG(l3rt->flags, BGP_VRF_RT_AUTO))
+ continue;
+
ecom_str = ecommunity_ecom2str(
- ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
+ l3rt->ecom, ECOMMUNITY_FORMAT_ROUTE_MAP, 0);
vty_out(vty, " route-target export %s\n", ecom_str);
XFREE(MTYPE_ECOMMUNITY_STR, ecom_str);
}
}
+
+ /* export route-target auto */
+ if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_EXPORT_AUTO_RT_CFGD))
+ vty_out(vty, " route-target export auto\n");
}
void bgp_ethernetvpn_init(void)
@@ -7181,6 +7417,8 @@ void bgp_ethernetvpn_init(void)
install_element(BGP_NODE, &no_bgp_evpn_vrf_rd_without_val_cmd);
install_element(BGP_EVPN_NODE, &bgp_evpn_vrf_rt_cmd);
install_element(BGP_EVPN_NODE, &no_bgp_evpn_vrf_rt_cmd);
+ install_element(BGP_EVPN_NODE, &bgp_evpn_vrf_rt_auto_cmd);
+ install_element(BGP_EVPN_NODE, &no_bgp_evpn_vrf_rt_auto_cmd);
install_element(BGP_EVPN_NODE, &bgp_evpn_ead_es_rt_cmd);
install_element(BGP_EVPN_NODE, &no_bgp_evpn_ead_es_rt_cmd);
install_element(BGP_EVPN_NODE, &bgp_evpn_ead_es_frag_evi_limit_cmd);
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index ddda10077..f110005e4 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -601,40 +601,41 @@ void bgp_delayopen_timer(struct thread *thread)
/* BGP Peer Down Cause */
const char *const peer_down_str[] = {"",
- "Router ID changed",
- "Remote AS changed",
- "Local AS change",
- "Cluster ID changed",
- "Confederation identifier changed",
- "Confederation peer changed",
- "RR client config change",
- "RS client config change",
- "Update source change",
- "Address family activated",
- "Admin. shutdown",
- "User reset",
- "BGP Notification received",
- "BGP Notification send",
- "Peer closed the session",
- "Neighbor deleted",
- "Peer-group add member",
- "Peer-group delete member",
- "Capability changed",
- "Passive config change",
- "Multihop config change",
- "NSF peer closed the session",
- "Intf peering v6only config change",
- "BFD down received",
- "Interface down",
- "Neighbor address lost",
- "Waiting for NHT",
- "Waiting for Peer IPv6 LLA",
- "Waiting for VRF to be initialized",
- "No AFI/SAFI activated for peer",
- "AS Set config change",
- "Waiting for peer OPEN",
- "Reached received prefix count",
- "Socket Error"};
+ "Router ID changed",
+ "Remote AS changed",
+ "Local AS change",
+ "Cluster ID changed",
+ "Confederation identifier changed",
+ "Confederation peer changed",
+ "RR client config change",
+ "RS client config change",
+ "Update source change",
+ "Address family activated",
+ "Admin. shutdown",
+ "User reset",
+ "BGP Notification received",
+ "BGP Notification send",
+ "Peer closed the session",
+ "Neighbor deleted",
+ "Peer-group add member",
+ "Peer-group delete member",
+ "Capability changed",
+ "Passive config change",
+ "Multihop config change",
+ "NSF peer closed the session",
+ "Intf peering v6only config change",
+ "BFD down received",
+ "Interface down",
+ "Neighbor address lost",
+ "No path to specified Neighbor",
+ "Waiting for Peer IPv6 LLA",
+ "Waiting for VRF to be initialized",
+ "No AFI/SAFI activated for peer",
+ "AS Set config change",
+ "Waiting for peer OPEN",
+ "Reached received prefix count",
+ "Socket Error",
+ "Admin. shutdown (RTT)"};
static void bgp_graceful_restart_timer_off(struct peer *peer)
{
@@ -1304,7 +1305,7 @@ void bgp_fsm_change_status(struct peer *peer, int status)
peer->rtt_keepalive_rcv = 0;
/* Fire backward transition hook if that's the case */
- if (peer->ostatus > peer->status)
+ if (peer->ostatus == Established && peer->status != Established)
hook_call(peer_backward_transition, peer);
/* Save event that caused status change. */
@@ -1330,6 +1331,9 @@ void bgp_fsm_change_status(struct peer *peer, int status)
&& bgp_update_delay_applicable(peer->bgp))
bgp_update_delay_process_status_change(peer);
+ /* BGP ORR : Update Active Root */
+ bgp_peer_update_orr_active_roots(peer);
+
if (bgp_debug_neighbor_events(peer))
zlog_debug("%s went from %s to %s", peer->host,
lookup_msg(bgp_status_msg, peer->ostatus, NULL),
@@ -1384,6 +1388,9 @@ int bgp_stop(struct peer *peer)
if (peer_established(peer)) {
peer->dropped++;
+ /* Notify BGP conditional advertisement process */
+ peer->advmap_table_change = true;
+
/* bgp log-neighbor-changes of neighbor Down */
if (CHECK_FLAG(peer->bgp->flags,
BGP_FLAG_LOG_NEIGHBOR_CHANGES)) {
@@ -1826,7 +1833,9 @@ int bgp_start(struct peer *peer)
flog_err(EC_BGP_FSM,
"%s [FSM] Trying to start suppressed peer - this is never supposed to happen!",
peer->host);
- if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN))
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_RTT_SHUTDOWN))
+ peer->last_reset = PEER_DOWN_RTT_SHUTDOWN;
+ else if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN))
peer->last_reset = PEER_DOWN_USER_SHUTDOWN;
else if (CHECK_FLAG(peer->bgp->flags, BGP_FLAG_SHUTDOWN))
peer->last_reset = PEER_DOWN_USER_SHUTDOWN;
@@ -1877,8 +1886,9 @@ int bgp_start(struct peer *peer)
if (!bgp_peer_reg_with_nht(peer)) {
if (bgp_zebra_num_connects()) {
if (bgp_debug_neighbor_events(peer))
- zlog_debug("%s [FSM] Waiting for NHT",
- peer->host);
+ zlog_debug(
+ "%s [FSM] Waiting for NHT, no path to neighbor present",
+ peer->host);
peer->last_reset = PEER_DOWN_WAITING_NHT;
BGP_EVENT_ADD(peer, TCP_connection_open_failed);
return 0;
diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h
index aaf6c480b..368c2c500 100644
--- a/bgpd/bgp_fsm.h
+++ b/bgpd/bgp_fsm.h
@@ -175,4 +175,6 @@ const char *print_peer_gr_cmd(enum peer_gr_command pr_gr_cmd);
const char *print_global_gr_mode(enum global_mode gl_mode);
const char *print_global_gr_cmd(enum global_gr_command gl_gr_cmd);
int bgp_peer_reg_with_nht(struct peer *peer);
+
+extern void bgp_peer_update_orr_active_roots(struct peer *peer);
#endif /* _QUAGGA_BGP_FSM_H */
diff --git a/bgpd/bgp_io.c b/bgpd/bgp_io.c
index f9bb8d518..49ae9816a 100644
--- a/bgpd/bgp_io.c
+++ b/bgpd/bgp_io.c
@@ -50,8 +50,9 @@ static void bgp_process_reads(struct thread *);
static bool validate_header(struct peer *);
/* generic i/o status codes */
-#define BGP_IO_TRANS_ERR (1 << 0) // EAGAIN or similar occurred
-#define BGP_IO_FATAL_ERR (1 << 1) // some kind of fatal TCP error
+#define BGP_IO_TRANS_ERR (1 << 0) /* EAGAIN or similar occurred */
+#define BGP_IO_FATAL_ERR (1 << 1) /* some kind of fatal TCP error */
+#define BGP_IO_WORK_FULL_ERR (1 << 2) /* No room in work buffer */
/* Thread external API ----------------------------------------------------- */
@@ -163,6 +164,58 @@ static void bgp_process_writes(struct thread *thread)
}
}
+static int read_ibuf_work(struct peer *peer)
+{
+ /* static buffer for transferring packets */
+ /* shorter alias to peer's input buffer */
+ struct ringbuf *ibw = peer->ibuf_work;
+ /* packet size as given by header */
+ uint16_t pktsize = 0;
+ struct stream *pkt;
+
+ /* Hold the I/O lock, we might not have space on the InQ */
+ frr_mutex_lock_autounlock(&peer->io_mtx);
+ /* ============================================== */
+
+ if (peer->ibuf->count >= bm->inq_limit)
+ return -ENOMEM;
+
+ /* check that we have enough data for a header */
+ if (ringbuf_remain(ibw) < BGP_HEADER_SIZE)
+ return 0;
+
+ /* check that header is valid */
+ if (!validate_header(peer))
+ return -EBADMSG;
+
+ /* header is valid; retrieve packet size */
+ ringbuf_peek(ibw, BGP_MARKER_SIZE, &pktsize, sizeof(pktsize));
+
+ pktsize = ntohs(pktsize);
+
+ /* if this fails we are seriously screwed */
+ assert(pktsize <= peer->max_packet_size);
+
+ /*
+ * If we have that much data, chuck it into its own
+ * stream and append to input queue for processing.
+ *
+ * Otherwise, come back later.
+ */
+ if (ringbuf_remain(ibw) < pktsize)
+ return 0;
+
+ pkt = stream_new(pktsize);
+ assert(STREAM_WRITEABLE(pkt) == pktsize);
+ assert(ringbuf_get(ibw, pkt->data, pktsize) == pktsize);
+ stream_set_endp(pkt, pktsize);
+
+ frrtrace(2, frr_bgp, packet_read, peer, pkt);
+ stream_fifo_push(peer->ibuf, pkt);
+
+ return pktsize;
+}
+
/*
* Called from I/O pthread when a file descriptor has become ready for reading,
* or has hung up.
@@ -173,12 +226,14 @@ static void bgp_process_writes(struct thread *thread)
static void bgp_process_reads(struct thread *thread)
{
/* clang-format off */
- static struct peer *peer; // peer to read from
- uint16_t status; // bgp_read status code
- bool more = true; // whether we got more data
- bool fatal = false; // whether fatal error occurred
- bool added_pkt = false; // whether we pushed onto ->ibuf
- int code = 0; // FSM code if error occurred
+ static struct peer *peer; /* peer to read from */
+ uint16_t status; /* bgp_read status code */
+ bool fatal = false; /* whether fatal error occurred */
+ bool added_pkt = false; /* whether we pushed onto ->ibuf */
+ int code = 0; /* FSM code if error occurred */
+ bool ibuf_full = false; /* Is peer fifo IN Buffer full */
+ static bool ibuf_full_logged; /* Have we logged full already */
+ int ret = 1;
/* clang-format on */
peer = THREAD_ARG(thread);
@@ -195,12 +250,11 @@ static void bgp_process_reads(struct thread *thread)
/* error checking phase */
if (CHECK_FLAG(status, BGP_IO_TRANS_ERR)) {
/* no problem; just don't process packets */
- more = false;
+ goto done;
}
if (CHECK_FLAG(status, BGP_IO_FATAL_ERR)) {
/* problem; tear down session */
- more = false;
fatal = true;
/* Handle the error in the main pthread, include the
@@ -208,67 +262,54 @@ static void bgp_process_reads(struct thread *thread)
*/
thread_add_event(bm->master, bgp_packet_process_error,
peer, code, &peer->t_process_packet_error);
+ goto done;
}
- while (more) {
- /* static buffer for transferring packets */
- /* shorter alias to peer's input buffer */
- struct ringbuf *ibw = peer->ibuf_work;
- /* packet size as given by header */
- uint16_t pktsize = 0;
-
- /* check that we have enough data for a header */
- if (ringbuf_remain(ibw) < BGP_HEADER_SIZE)
+ while (true) {
+ ret = read_ibuf_work(peer);
+ if (ret <= 0)
break;
- /* check that header is valid */
- if (!validate_header(peer)) {
- fatal = true;
- break;
- }
-
- /* header is valid; retrieve packet size */
- ringbuf_peek(ibw, BGP_MARKER_SIZE, &pktsize, sizeof(pktsize));
-
- pktsize = ntohs(pktsize);
-
- /* if this fails we are seriously screwed */
- assert(pktsize <= peer->max_packet_size);
-
- /*
- * If we have that much data, chuck it into its own
- * stream and append to input queue for processing.
- */
- if (ringbuf_remain(ibw) >= pktsize) {
- struct stream *pkt = stream_new(pktsize);
-
- assert(STREAM_WRITEABLE(pkt) == pktsize);
- assert(ringbuf_get(ibw, pkt->data, pktsize) == pktsize);
- stream_set_endp(pkt, pktsize);
-
- frrtrace(2, frr_bgp, packet_read, peer, pkt);
- frr_with_mutex (&peer->io_mtx) {
- stream_fifo_push(peer->ibuf, pkt);
- }
+ added_pkt = true;
+ }
- added_pkt = true;
- } else
- break;
+ switch (ret) {
+ case -EBADMSG:
+ fatal = true;
+ break;
+ case -ENOMEM:
+ ibuf_full = true;
+ if (!ibuf_full_logged) {
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug(
+ "%s [Event] Peer Input-Queue is full: limit (%u)",
+ peer->host, bm->inq_limit);
+
+ ibuf_full_logged = true;
+ }
+ break;
+ default:
+ ibuf_full_logged = false;
+ break;
}
+done:
/* handle invalid header */
if (fatal) {
/* wipe buffer just in case someone screwed up */
ringbuf_wipe(peer->ibuf_work);
- } else {
+ return;
+ }
+
+ /* ringbuf should be fully drained unless ibuf is full */
+ if (!ibuf_full)
assert(ringbuf_space(peer->ibuf_work) >= peer->max_packet_size);
- thread_add_read(fpt->master, bgp_process_reads, peer, peer->fd,
- &peer->t_read);
- if (added_pkt)
- thread_add_event(bm->master, bgp_process_packet,
- peer, 0, &peer->t_process_packet);
- }
+ thread_add_read(fpt->master, bgp_process_reads, peer, peer->fd,
+ &peer->t_read);
+ if (added_pkt)
+ thread_add_event(bm->master, bgp_process_packet, peer, 0,
+ &peer->t_process_packet);
}
/*
@@ -462,12 +503,20 @@ done : {
*/
static uint16_t bgp_read(struct peer *peer, int *code_p)
{
- size_t readsize; // how many bytes we want to read
- ssize_t nbytes; // how many bytes we actually read
+ size_t readsize; /* how many bytes we want to read */
+ ssize_t nbytes; /* how many bytes we actually read */
+ size_t ibuf_work_space; /* space we can read into the work buf */
uint16_t status = 0;
- readsize =
- MIN(ringbuf_space(peer->ibuf_work), sizeof(peer->ibuf_scratch));
+ ibuf_work_space = ringbuf_space(peer->ibuf_work);
+
+ if (ibuf_work_space == 0) {
+ SET_FLAG(status, BGP_IO_WORK_FULL_ERR);
+ return status;
+ }
+
+ readsize = MIN(ibuf_work_space, sizeof(peer->ibuf_scratch));
+
nbytes = read(peer->fd, peer->ibuf_scratch, readsize);
/* EAGAIN or EWOULDBLOCK; come back later */
diff --git a/bgpd/bgp_labelpool.c b/bgpd/bgp_labelpool.c
index c227a5e41..129878451 100644
--- a/bgpd/bgp_labelpool.c
+++ b/bgpd/bgp_labelpool.c
@@ -39,9 +39,7 @@
#define BGP_LABELPOOL_ENABLE_TESTS 0
-#ifndef VTYSH_EXTRACT_PL
#include "bgpd/bgp_labelpool_clippy.c"
-#endif
/*
diff --git a/bgpd/bgp_mac.c b/bgpd/bgp_mac.c
index 02b7e6486..b9649ac4d 100644
--- a/bgpd/bgp_mac.c
+++ b/bgpd/bgp_mac.c
@@ -242,19 +242,18 @@ static void bgp_mac_rescan_evpn_table(struct bgp *bgp, struct ethaddr *macaddr)
if (!peer_established(peer))
continue;
- if (CHECK_FLAG(peer->af_flags[afi][safi],
- PEER_FLAG_SOFT_RECONFIG)) {
- if (bgp_debug_update(peer, NULL, NULL, 1))
- zlog_debug("Processing EVPN MAC interface change on peer %s (inbound, soft-reconfig)",
- peer->host);
-
- bgp_soft_reconfig_in(peer, afi, safi);
- } else {
+ if (bgp_debug_update(peer, NULL, NULL, 1))
+ zlog_debug(
+ "Processing EVPN MAC interface change on peer %s %s",
+ peer->host,
+ CHECK_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_SOFT_RECONFIG)
+ ? "(inbound, soft-reconfig)"
+ : "");
+
+ if (!bgp_soft_reconfig_in(peer, afi, safi)) {
struct bgp_table *table = bgp->rib[afi][safi];
- if (bgp_debug_update(peer, NULL, NULL, 1))
- zlog_debug("Processing EVPN MAC interface change on peer %s",
- peer->host);
bgp_process_mac_rescan_table(bgp, peer, table, macaddr);
}
}
diff --git a/bgpd/bgp_memory.c b/bgpd/bgp_memory.c
index 850657d35..ced3e1890 100644
--- a/bgpd/bgp_memory.c
+++ b/bgpd/bgp_memory.c
@@ -134,8 +134,12 @@ DEFINE_MTYPE(BGPD, BGP_EVPN_VRF_IMPORT_RT, "BGP EVPN VRF Import RT");
DEFINE_MTYPE(BGPD, BGP_SRV6_L3VPN, "BGP prefix-sid srv6 l3vpn servcie");
DEFINE_MTYPE(BGPD, BGP_SRV6_VPN, "BGP prefix-sid srv6 vpn service");
+
DEFINE_MTYPE(BGPD, BGP_SRV6_SID, "BGP srv6 segment-id");
DEFINE_MTYPE(BGPD, BGP_SRV6_FUNCTION, "BGP srv6 function");
DEFINE_MTYPE(BGPD, EVPN_REMOTE_IP, "BGP EVPN Remote IP hash entry");
DEFINE_MTYPE(BGPD, BGP_NOTIFICATION, "BGP Notification Message");
+DEFINE_MTYPE(BGPD, BGP_ORR_GROUP, "BGP Optimal Route Reflection Group");
+DEFINE_MTYPE(BGPD, BGP_ORR_GROUP_NAME,
+ "BGP Optimal Route Reflection Group Name");
diff --git a/bgpd/bgp_memory.h b/bgpd/bgp_memory.h
index 510cfa21c..990c6e1fa 100644
--- a/bgpd/bgp_memory.h
+++ b/bgpd/bgp_memory.h
@@ -137,5 +137,7 @@ DECLARE_MTYPE(BGP_SRV6_FUNCTION);
DECLARE_MTYPE(EVPN_REMOTE_IP);
DECLARE_MTYPE(BGP_NOTIFICATION);
+DECLARE_MTYPE(BGP_ORR_GROUP);
+DECLARE_MTYPE(BGP_ORR_GROUP_NAME);
#endif /* _QUAGGA_BGP_MEMORY_H */
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index d7fd4bc77..18cb90763 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -42,6 +42,7 @@
#include "bgpd/bgp_packet.h"
#include "bgpd/bgp_vty.h"
#include "bgpd/bgp_vpn.h"
+#include "bgpd/bgp_community.h"
#include "bgpd/bgp_ecommunity.h"
#include "bgpd/bgp_zebra.h"
#include "bgpd/bgp_nexthop.h"
@@ -359,7 +360,7 @@ void vpn_leak_zebra_vrf_label_withdraw(struct bgp *bgp, afi_t afi)
* leaked to VPN. Zebra should install this srv6-function in the kernel with
* an action of "End.DT4/6's IP FIB to route the PDU."
*/
-void vpn_leak_zebra_vrf_sid_update(struct bgp *bgp, afi_t afi)
+void vpn_leak_zebra_vrf_sid_update_per_af(struct bgp *bgp, afi_t afi)
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
enum seg6local_action_t act;
@@ -367,7 +368,6 @@ void vpn_leak_zebra_vrf_sid_update(struct bgp *bgp, afi_t afi)
struct in6_addr *tovpn_sid = NULL;
struct in6_addr *tovpn_sid_ls = NULL;
struct vrf *vrf;
- char buf[256] = {0};
if (bgp->vrf_id == VRF_UNKNOWN) {
if (debug)
@@ -384,12 +384,10 @@ void vpn_leak_zebra_vrf_sid_update(struct bgp *bgp, afi_t afi)
return;
}
- if (debug) {
- inet_ntop(AF_INET6, tovpn_sid, buf, sizeof(buf));
- zlog_debug("%s: vrf %s: afi %s: setting sid %s for vrf id %d",
- __func__, bgp->name_pretty, afi2str(afi), buf,
+ if (debug)
+ zlog_debug("%s: vrf %s: afi %s: setting sid %pI6 for vrf id %d",
+ __func__, bgp->name_pretty, afi2str(afi), tovpn_sid,
bgp->vrf_id);
- }
vrf = vrf_lookup_by_id(bgp->vrf_id);
if (!vrf)
@@ -406,10 +404,77 @@ void vpn_leak_zebra_vrf_sid_update(struct bgp *bgp, afi_t afi)
}
/*
+ * This function informs zebra of the srv6-function this vrf sets on routes
+ * leaked to VPN. Zebra should install this srv6-function in the kernel with
+ * an action of "End.DT46's IP FIB to route the PDU."
+ */
+void vpn_leak_zebra_vrf_sid_update_per_vrf(struct bgp *bgp)
+{
+ int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
+ enum seg6local_action_t act;
+ struct seg6local_context ctx = {};
+ struct in6_addr *tovpn_sid = NULL;
+ struct in6_addr *tovpn_sid_ls = NULL;
+ struct vrf *vrf;
+
+ if (bgp->vrf_id == VRF_UNKNOWN) {
+ if (debug)
+ zlog_debug(
+ "%s: vrf %s: vrf_id not set, can't set zebra vrf label",
+ __func__, bgp->name_pretty);
+ return;
+ }
+
+ tovpn_sid = bgp->tovpn_sid;
+ if (!tovpn_sid) {
+ if (debug)
+ zlog_debug("%s: vrf %s: sid not set", __func__,
+ bgp->name_pretty);
+ return;
+ }
+
+ if (debug)
+ zlog_debug("%s: vrf %s: setting sid %pI6 for vrf id %d",
+ __func__, bgp->name_pretty, tovpn_sid, bgp->vrf_id);
+
+ vrf = vrf_lookup_by_id(bgp->vrf_id);
+ if (!vrf)
+ return;
+
+ ctx.table = vrf->data.l.table_id;
+ act = ZEBRA_SEG6_LOCAL_ACTION_END_DT46;
+ zclient_send_localsid(zclient, tovpn_sid, bgp->vrf_id, act, &ctx);
+
+ tovpn_sid_ls = XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr));
+ *tovpn_sid_ls = *tovpn_sid;
+ bgp->tovpn_zebra_vrf_sid_last_sent = tovpn_sid_ls;
+}
+
+/*
+ * This function informs zebra of the srv6-function this vrf sets on routes
+ * leaked to VPN. Zebra should install this srv6-function in the kernel with
+ * an action of "End.DT4/6/46's IP FIB to route the PDU."
+ */
+void vpn_leak_zebra_vrf_sid_update(struct bgp *bgp, afi_t afi)
+{
+ int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
+
+ if (bgp->vpn_policy[afi].tovpn_sid)
+ return vpn_leak_zebra_vrf_sid_update_per_af(bgp, afi);
+
+ if (bgp->tovpn_sid)
+ return vpn_leak_zebra_vrf_sid_update_per_vrf(bgp);
+
+ if (debug)
+ zlog_debug("%s: vrf %s: afi %s: sid not set", __func__,
+ bgp->name_pretty, afi2str(afi));
+}
+
+/*
* If zebra tells us vrf has become unconfigured, tell zebra not to
* use this srv6-function to forward to the vrf anymore
*/
-void vpn_leak_zebra_vrf_sid_withdraw(struct bgp *bgp, afi_t afi)
+void vpn_leak_zebra_vrf_sid_withdraw_per_af(struct bgp *bgp, afi_t afi)
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
@@ -431,6 +496,45 @@ void vpn_leak_zebra_vrf_sid_withdraw(struct bgp *bgp, afi_t afi)
bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent);
}
+/*
+ * If zebra tells us vrf has become unconfigured, tell zebra not to
+ * use this srv6-function to forward to the vrf anymore
+ */
+void vpn_leak_zebra_vrf_sid_withdraw_per_vrf(struct bgp *bgp)
+{
+ int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
+
+ if (bgp->vrf_id == VRF_UNKNOWN) {
+ if (debug)
+ zlog_debug(
+ "%s: vrf %s: vrf_id not set, can't set zebra vrf label",
+ __func__, bgp->name_pretty);
+ return;
+ }
+
+ if (debug)
+ zlog_debug("%s: deleting sid for vrf %s (id=%d)", __func__,
+ bgp->name_pretty, bgp->vrf_id);
+
+ zclient_send_localsid(zclient, bgp->tovpn_zebra_vrf_sid_last_sent,
+ bgp->vrf_id, ZEBRA_SEG6_LOCAL_ACTION_UNSPEC,
+ NULL);
+ XFREE(MTYPE_BGP_SRV6_SID, bgp->tovpn_zebra_vrf_sid_last_sent);
+}
+
+/*
+ * If zebra tells us vrf has become unconfigured, tell zebra not to
+ * use this srv6-function to forward to the vrf anymore
+ */
+void vpn_leak_zebra_vrf_sid_withdraw(struct bgp *bgp, afi_t afi)
+{
+ if (bgp->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent)
+ vpn_leak_zebra_vrf_sid_withdraw_per_af(bgp, afi);
+
+ if (bgp->tovpn_zebra_vrf_sid_last_sent)
+ vpn_leak_zebra_vrf_sid_withdraw_per_vrf(bgp);
+}
+
int vpn_leak_label_callback(
mpls_label_t label,
void *labelid,
@@ -504,6 +608,18 @@ static void sid_register(struct bgp *bgp, const struct in6_addr *sid,
listnode_add(bgp->srv6_functions, func);
}
+static void sid_unregister(struct bgp *bgp, const struct in6_addr *sid)
+{
+ struct listnode *node, *nnode;
+ struct bgp_srv6_function *func;
+
+ for (ALL_LIST_ELEMENTS(bgp->srv6_functions, node, nnode, func))
+ if (sid_same(&func->sid, sid)) {
+ listnode_delete(bgp->srv6_functions, func);
+ XFREE(MTYPE_BGP_SRV6_FUNCTION, func);
+ }
+}
+
static bool sid_exist(struct bgp *bgp, const struct in6_addr *sid)
{
struct listnode *node;
@@ -524,37 +640,77 @@ static bool sid_exist(struct bgp *bgp, const struct in6_addr *sid)
* else: try to allocate as auto-mode
*/
static uint32_t alloc_new_sid(struct bgp *bgp, uint32_t index,
- struct in6_addr *sid_locator,
+ struct srv6_locator_chunk *sid_locator_chunk,
struct in6_addr *sid)
{
+ int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL);
struct listnode *node;
struct srv6_locator_chunk *chunk;
bool alloced = false;
int label = 0;
uint8_t offset = 0;
- uint8_t len = 0;
+ uint8_t func_len = 0, shift_len = 0;
+ uint32_t index_max = 0;
- if (!bgp || !sid_locator || !sid)
+ if (!bgp || !sid_locator_chunk || !sid)
return false;
for (ALL_LIST_ELEMENTS_RO(bgp->srv6_locator_chunks, node, chunk)) {
- *sid_locator = chunk->prefix.prefix;
+ if (chunk->function_bits_length >
+ BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH) {
+ if (debug)
+ zlog_debug(
+ "%s: invalid SRv6 Locator chunk (%pFX): Function Length must be less or equal to %d",
+ __func__, &chunk->prefix,
+ BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH);
+ continue;
+ }
+
+ index_max = (1 << chunk->function_bits_length) - 1;
+
+ if (index > index_max) {
+ if (debug)
+ zlog_debug(
+ "%s: skipped SRv6 Locator chunk (%pFX): Function Length is too short to support specified index (%u)",
+ __func__, &chunk->prefix, index);
+ continue;
+ }
+
*sid = chunk->prefix.prefix;
+ *sid_locator_chunk = *chunk;
offset = chunk->block_bits_length + chunk->node_bits_length;
- len = chunk->function_bits_length ?: 16;
+ func_len = chunk->function_bits_length;
+ shift_len = BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH - func_len;
if (index != 0) {
- label = index << 12;
- transpose_sid(sid, label, offset, len);
+ label = index << shift_len;
+ if (label < MPLS_LABEL_UNRESERVED_MIN) {
+ if (debug)
+ zlog_debug(
+ "%s: skipped to allocate SRv6 SID (%pFX): Label (%u) is too small to use",
+ __func__, &chunk->prefix,
+ label);
+ continue;
+ }
+
+ transpose_sid(sid, label, offset, func_len);
if (sid_exist(bgp, sid))
- return false;
+ continue;
alloced = true;
break;
}
- for (size_t i = 1; i < 255; i++) {
- label = i << 12;
- transpose_sid(sid, label, offset, len);
+ for (uint32_t i = 1; i < index_max; i++) {
+ label = i << shift_len;
+ if (label < MPLS_LABEL_UNRESERVED_MIN) {
+ if (debug)
+ zlog_debug(
+ "%s: skipped to allocate SRv6 SID (%pFX): Label (%u) is too small to use",
+ __func__, &chunk->prefix,
+ label);
+ continue;
+ }
+ transpose_sid(sid, label, offset, func_len);
if (sid_exist(bgp, sid))
continue;
alloced = true;
@@ -569,11 +725,12 @@ static uint32_t alloc_new_sid(struct bgp *bgp, uint32_t index,
return label;
}
-void ensure_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi)
+void ensure_vrf_tovpn_sid_per_af(struct bgp *bgp_vpn, struct bgp *bgp_vrf,
+ afi_t afi)
{
int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
- char buf[256];
- struct in6_addr *tovpn_sid, *tovpn_sid_locator;
+ struct srv6_locator_chunk *tovpn_sid_locator;
+ struct in6_addr *tovpn_sid;
uint32_t tovpn_sid_index = 0, tovpn_sid_transpose_label;
bool tovpn_sid_auto = false;
@@ -607,27 +764,26 @@ void ensure_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi)
return;
}
- tovpn_sid_locator =
- XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr));
+ tovpn_sid_locator = srv6_locator_chunk_alloc();
tovpn_sid = XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr));
tovpn_sid_transpose_label = alloc_new_sid(bgp_vpn, tovpn_sid_index,
tovpn_sid_locator, tovpn_sid);
if (tovpn_sid_transpose_label == 0) {
- zlog_debug("%s: not allocated new sid for vrf %s: afi %s",
- __func__, bgp_vrf->name_pretty, afi2str(afi));
- XFREE(MTYPE_BGP_SRV6_SID, tovpn_sid_locator);
+ if (debug)
+ zlog_debug(
+ "%s: not allocated new sid for vrf %s: afi %s",
+ __func__, bgp_vrf->name_pretty, afi2str(afi));
+ srv6_locator_chunk_free(&tovpn_sid_locator);
XFREE(MTYPE_BGP_SRV6_SID, tovpn_sid);
return;
}
- if (debug) {
- inet_ntop(AF_INET6, tovpn_sid, buf, sizeof(buf));
- zlog_debug("%s: new sid %s allocated for vrf %s: afi %s",
- __func__, buf, bgp_vrf->name_pretty,
+ if (debug)
+ zlog_debug("%s: new sid %pI6 allocated for vrf %s: afi %s",
+ __func__, tovpn_sid, bgp_vrf->name_pretty,
afi2str(afi));
- }
bgp_vrf->vpn_policy[afi].tovpn_sid = tovpn_sid;
bgp_vrf->vpn_policy[afi].tovpn_sid_locator = tovpn_sid_locator;
@@ -635,21 +791,167 @@ void ensure_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi)
tovpn_sid_transpose_label;
}
+void ensure_vrf_tovpn_sid_per_vrf(struct bgp *bgp_vpn, struct bgp *bgp_vrf)
+{
+ int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
+ struct srv6_locator_chunk *tovpn_sid_locator;
+ struct in6_addr *tovpn_sid;
+ uint32_t tovpn_sid_index = 0, tovpn_sid_transpose_label;
+ bool tovpn_sid_auto = false;
+
+ if (debug)
+ zlog_debug("%s: try to allocate new SID for vrf %s", __func__,
+ bgp_vrf->name_pretty);
+
+ /* skip when tovpn sid is already allocated on vrf instance */
+ if (bgp_vrf->tovpn_sid)
+ return;
+
+ /*
+ * skip when bgp vpn instance ins't allocated
+ * or srv6 locator chunk isn't allocated
+ */
+ if (!bgp_vpn || !bgp_vpn->srv6_locator_chunks)
+ return;
+
+ tovpn_sid_index = bgp_vrf->tovpn_sid_index;
+ tovpn_sid_auto = CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_TOVPN_SID_AUTO);
+
+ /* skip when VPN isn't configured on vrf-instance */
+ if (tovpn_sid_index == 0 && !tovpn_sid_auto)
+ return;
+
+ /* check invalid case both configured index and auto */
+ if (tovpn_sid_index != 0 && tovpn_sid_auto) {
+ zlog_err("%s: index-mode and auto-mode both selected. ignored.",
+ __func__);
+ return;
+ }
+
+ tovpn_sid_locator = srv6_locator_chunk_alloc();
+ tovpn_sid = XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr));
+
+ tovpn_sid_transpose_label = alloc_new_sid(bgp_vpn, tovpn_sid_index,
+ tovpn_sid_locator, tovpn_sid);
+
+ if (tovpn_sid_transpose_label == 0) {
+ if (debug)
+ zlog_debug("%s: not allocated new sid for vrf %s",
+ __func__, bgp_vrf->name_pretty);
+ srv6_locator_chunk_free(&tovpn_sid_locator);
+ XFREE(MTYPE_BGP_SRV6_SID, tovpn_sid);
+ return;
+ }
+
+ if (debug)
+ zlog_debug("%s: new sid %pI6 allocated for vrf %s", __func__,
+ tovpn_sid, bgp_vrf->name_pretty);
+
+ bgp_vrf->tovpn_sid = tovpn_sid;
+ bgp_vrf->tovpn_sid_locator = tovpn_sid_locator;
+ bgp_vrf->tovpn_sid_transpose_label = tovpn_sid_transpose_label;
+}
+
+void ensure_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi)
+{
+ /* per-af sid */
+ if (bgp_vrf->vpn_policy[afi].tovpn_sid_index != 0 ||
+ CHECK_FLAG(bgp_vrf->vpn_policy[afi].flags,
+ BGP_VPN_POLICY_TOVPN_SID_AUTO))
+ return ensure_vrf_tovpn_sid_per_af(bgp_vpn, bgp_vrf, afi);
+
+ /* per-vrf sid */
+ if (bgp_vrf->tovpn_sid_index != 0 ||
+ CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_TOVPN_SID_AUTO))
+ return ensure_vrf_tovpn_sid_per_vrf(bgp_vpn, bgp_vrf);
+}
+
+void delete_vrf_tovpn_sid_per_af(struct bgp *bgp_vpn, struct bgp *bgp_vrf,
+ afi_t afi)
+{
+ int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
+ uint32_t tovpn_sid_index = 0;
+ bool tovpn_sid_auto = false;
+
+ if (debug)
+ zlog_debug("%s: try to remove SID for vrf %s: afi %s", __func__,
+ bgp_vrf->name_pretty, afi2str(afi));
+
+ tovpn_sid_index = bgp_vrf->vpn_policy[afi].tovpn_sid_index;
+ tovpn_sid_auto = CHECK_FLAG(bgp_vrf->vpn_policy[afi].flags,
+ BGP_VPN_POLICY_TOVPN_SID_AUTO);
+
+ /* skip when VPN is configured on vrf-instance */
+ if (tovpn_sid_index != 0 || tovpn_sid_auto)
+ return;
+
+ srv6_locator_chunk_free(&bgp_vrf->vpn_policy[afi].tovpn_sid_locator);
+
+ if (bgp_vrf->vpn_policy[afi].tovpn_sid) {
+ sid_unregister(bgp_vrf, bgp_vrf->vpn_policy[afi].tovpn_sid);
+ XFREE(MTYPE_BGP_SRV6_SID, bgp_vrf->vpn_policy[afi].tovpn_sid);
+ }
+ bgp_vrf->vpn_policy[afi].tovpn_sid_transpose_label = 0;
+}
+
+void delete_vrf_tovpn_sid_per_vrf(struct bgp *bgp_vpn, struct bgp *bgp_vrf)
+{
+ int debug = BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF);
+ uint32_t tovpn_sid_index = 0;
+ bool tovpn_sid_auto = false;
+
+ if (debug)
+ zlog_debug("%s: try to remove SID for vrf %s", __func__,
+ bgp_vrf->name_pretty);
+
+ tovpn_sid_index = bgp_vrf->tovpn_sid_index;
+ tovpn_sid_auto =
+ CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VPN_POLICY_TOVPN_SID_AUTO);
+
+ /* skip when VPN is configured on vrf-instance */
+ if (tovpn_sid_index != 0 || tovpn_sid_auto)
+ return;
+
+ srv6_locator_chunk_free(&bgp_vrf->tovpn_sid_locator);
+
+ if (bgp_vrf->tovpn_sid) {
+ sid_unregister(bgp_vrf, bgp_vrf->tovpn_sid);
+ XFREE(MTYPE_BGP_SRV6_SID, bgp_vrf->tovpn_sid);
+ }
+ bgp_vrf->tovpn_sid_transpose_label = 0;
+}
+
+void delete_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi)
+{
+ delete_vrf_tovpn_sid_per_af(bgp_vpn, bgp_vrf, afi);
+ delete_vrf_tovpn_sid_per_vrf(bgp_vpn, bgp_vrf);
+}
+
/*
- * This function shifts "label" 4 bits to the right and
- * embeds it by length "len", starting at offset "offset"
- * as seen from the MSB (Most Significant Bit) of "sid".
+ * This function embeds upper `len` bits of `label` in `sid`,
+ * starting at offset `offset` as seen from the MSB of `sid`.
*
- * e.g. if "label" is 0x1000 and "len" is 16, "label" is
- * embedded in "sid" as follows:
+ * e.g. Given that `label` is 0x12345 and `len` is 16,
+ * then `label` will be embedded in `sid` as follows:
*
* <---- len ----->
- * label: 0000 0001 0000 0000 0000
- * sid: .... 0000 0001 0000 0000
+ * label: 0001 0002 0003 0004 0005
+ * sid: .... 0001 0002 0003 0004
* <---- len ----->
* ^
* |
* offset from MSB
+ *
+ * e.g. Given that `label` is 0x12345 and `len` is 8,
+ * `label` will be embedded in `sid` as follows:
+ *
+ * <- len ->
+ * label: 0001 0002 0003 0004 0005
+ * sid: .... 0001 0002 0000 0000
+ * <- len ->
+ * ^
+ * |
+ * offset from MSB
*/
void transpose_sid(struct in6_addr *sid, uint32_t label, uint8_t offset,
uint8_t len)
@@ -657,7 +959,7 @@ void transpose_sid(struct in6_addr *sid, uint32_t label, uint8_t offset,
for (uint8_t idx = 0; idx < len; idx++) {
uint8_t tidx = offset + idx;
sid->s6_addr[tidx / 8] &= ~(0x1 << (7 - tidx % 8));
- if (label >> (len + 3 - idx) & 0x1)
+ if (label >> (19 - idx) & 0x1)
sid->s6_addr[tidx / 8] |= 0x1 << (7 - tidx % 8);
}
}
@@ -946,6 +1248,9 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn,
if (nexthop_self_flag)
bgp_path_info_set_flag(bn, bpi, BGP_PATH_ANNC_NH_SELF);
+ if (CHECK_FLAG(source_bpi->flags, BGP_PATH_ACCEPT_OWN))
+ bgp_path_info_set_flag(bn, bpi, BGP_PATH_ACCEPT_OWN);
+
if (leak_update_nexthop_valid(to_bgp, bn, new_attr, afi, safi,
source_bpi, bpi, bgp_orig, p,
debug))
@@ -986,6 +1291,9 @@ leak_update(struct bgp *to_bgp, struct bgp_dest *bn,
if (nexthop_self_flag)
bgp_path_info_set_flag(bn, new, BGP_PATH_ANNC_NH_SELF);
+ if (CHECK_FLAG(source_bpi->flags, BGP_PATH_ACCEPT_OWN))
+ bgp_path_info_set_flag(bn, new, BGP_PATH_ACCEPT_OWN);
+
bgp_path_info_extra_get(new);
/*
@@ -1167,6 +1475,8 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */
XFREE(MTYPE_ECOMMUNITY_STR, s);
}
+ community_strip_accept_own(&static_attr);
+
/* Nexthop */
/* if policy nexthop not set, use 0 */
if (CHECK_FLAG(from_bgp->vpn_policy[afi].flags,
@@ -1244,27 +1554,74 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */
/* Set SID for SRv6 VPN */
if (from_bgp->vpn_policy[afi].tovpn_sid_locator) {
+ struct srv6_locator_chunk *locator =
+ from_bgp->vpn_policy[afi].tovpn_sid_locator;
encode_label(
from_bgp->vpn_policy[afi].tovpn_sid_transpose_label,
&label);
static_attr.srv6_l3vpn = XCALLOC(MTYPE_BGP_SRV6_L3VPN,
sizeof(struct bgp_attr_srv6_l3vpn));
static_attr.srv6_l3vpn->sid_flags = 0x00;
- static_attr.srv6_l3vpn->endpoint_behavior = 0xffff;
+ static_attr.srv6_l3vpn->endpoint_behavior =
+ afi == AFI_IP
+ ? (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)
+ ? SRV6_ENDPOINT_BEHAVIOR_END_DT4_USID
+ : SRV6_ENDPOINT_BEHAVIOR_END_DT4)
+ : (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)
+ ? SRV6_ENDPOINT_BEHAVIOR_END_DT6_USID
+ : SRV6_ENDPOINT_BEHAVIOR_END_DT6);
+ static_attr.srv6_l3vpn->loc_block_len =
+ from_bgp->vpn_policy[afi]
+ .tovpn_sid_locator->block_bits_length;
+ static_attr.srv6_l3vpn->loc_node_len =
+ from_bgp->vpn_policy[afi]
+ .tovpn_sid_locator->node_bits_length;
+ static_attr.srv6_l3vpn->func_len =
+ from_bgp->vpn_policy[afi]
+ .tovpn_sid_locator->function_bits_length;
+ static_attr.srv6_l3vpn->arg_len =
+ from_bgp->vpn_policy[afi]
+ .tovpn_sid_locator->argument_bits_length;
+ static_attr.srv6_l3vpn->transposition_len =
+ from_bgp->vpn_policy[afi]
+ .tovpn_sid_locator->function_bits_length;
+ static_attr.srv6_l3vpn->transposition_offset =
+ from_bgp->vpn_policy[afi]
+ .tovpn_sid_locator->block_bits_length +
+ from_bgp->vpn_policy[afi]
+ .tovpn_sid_locator->node_bits_length;
+ ;
+ memcpy(&static_attr.srv6_l3vpn->sid,
+ &from_bgp->vpn_policy[afi]
+ .tovpn_sid_locator->prefix.prefix,
+ sizeof(struct in6_addr));
+ } else if (from_bgp->tovpn_sid_locator) {
+ struct srv6_locator_chunk *locator =
+ from_bgp->tovpn_sid_locator;
+ encode_label(from_bgp->tovpn_sid_transpose_label, &label);
+ static_attr.srv6_l3vpn =
+ XCALLOC(MTYPE_BGP_SRV6_L3VPN,
+ sizeof(struct bgp_attr_srv6_l3vpn));
+ static_attr.srv6_l3vpn->sid_flags = 0x00;
+ static_attr.srv6_l3vpn->endpoint_behavior =
+ CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)
+ ? SRV6_ENDPOINT_BEHAVIOR_END_DT46_USID
+ : SRV6_ENDPOINT_BEHAVIOR_END_DT46;
static_attr.srv6_l3vpn->loc_block_len =
- BGP_PREFIX_SID_SRV6_LOCATOR_BLOCK_LENGTH;
+ from_bgp->tovpn_sid_locator->block_bits_length;
static_attr.srv6_l3vpn->loc_node_len =
- BGP_PREFIX_SID_SRV6_LOCATOR_NODE_LENGTH;
+ from_bgp->tovpn_sid_locator->node_bits_length;
static_attr.srv6_l3vpn->func_len =
- BGP_PREFIX_SID_SRV6_FUNCTION_LENGTH;
+ from_bgp->tovpn_sid_locator->function_bits_length;
static_attr.srv6_l3vpn->arg_len =
- BGP_PREFIX_SID_SRV6_ARGUMENT_LENGTH;
+ from_bgp->tovpn_sid_locator->argument_bits_length;
static_attr.srv6_l3vpn->transposition_len =
- BGP_PREFIX_SID_SRV6_TRANSPOSITION_LENGTH;
+ from_bgp->tovpn_sid_locator->function_bits_length;
static_attr.srv6_l3vpn->transposition_offset =
- BGP_PREFIX_SID_SRV6_TRANSPOSITION_OFFSET;
+ from_bgp->tovpn_sid_locator->block_bits_length +
+ from_bgp->tovpn_sid_locator->node_bits_length;
memcpy(&static_attr.srv6_l3vpn->sid,
- from_bgp->vpn_policy[afi].tovpn_sid_locator,
+ &from_bgp->tovpn_sid_locator->prefix.prefix,
sizeof(struct in6_addr));
}
@@ -1302,7 +1659,7 @@ void vpn_leak_from_vrf_update(struct bgp *to_bgp, /* to */
* because of loop checking.
*/
if (new_info)
- vpn_leak_to_vrf_update(from_bgp, new_info);
+ vpn_leak_to_vrf_update(from_bgp, new_info, NULL);
}
void vpn_leak_from_vrf_withdraw(struct bgp *to_bgp, /* to */
@@ -1458,10 +1815,40 @@ void vpn_leak_from_vrf_update_all(struct bgp *to_bgp, struct bgp *from_bgp,
}
}
-static bool
-vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
- struct bgp *from_bgp, /* from */
- struct bgp_path_info *path_vpn) /* route */
+static struct bgp *bgp_lookup_by_rd(struct bgp_path_info *bpi,
+ struct prefix_rd *rd, afi_t afi)
+{
+ struct listnode *node, *nnode;
+ struct bgp *bgp;
+
+ if (!rd)
+ return NULL;
+
+ /* If ACCEPT_OWN is not enabled for this path - return. */
+ if (!CHECK_FLAG(bpi->flags, BGP_PATH_ACCEPT_OWN))
+ return NULL;
+
+ for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
+ if (bgp->inst_type != BGP_INSTANCE_TYPE_VRF)
+ continue;
+
+ if (!CHECK_FLAG(bgp->vpn_policy[afi].flags,
+ BGP_VPN_POLICY_TOVPN_RD_SET))
+ continue;
+
+ /* Check if we have source VRF by RD value */
+ if (memcmp(&bgp->vpn_policy[afi].tovpn_rd.val, rd->val,
+ ECOMMUNITY_SIZE) == 0)
+ return bgp;
+ }
+
+ return NULL;
+}
+
+static bool vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
+ struct bgp *from_bgp, /* from */
+ struct bgp_path_info *path_vpn,
+ struct prefix_rd *prd)
{
const struct prefix *p = bgp_dest_get_prefix(path_vpn->net);
afi_t afi = family2afi(p->family);
@@ -1498,9 +1885,22 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
return false;
}
+ /* A route MUST NOT ever be accepted back into its source VRF, even if
+ * it carries one or more RTs that match that VRF.
+ */
+ if (prd && memcmp(&prd->val, &to_bgp->vpn_policy[afi].tovpn_rd.val,
+ ECOMMUNITY_SIZE) == 0) {
+ if (debug)
+ zlog_debug(
+ "%s: skipping import, match RD (%pRD) of src VRF (%s) and the prefix (%pFX)",
+ __func__, prd, to_bgp->name_pretty, p);
+
+ return false;
+ }
+
if (debug)
- zlog_debug("%s: updating %pFX to vrf %s", __func__, p,
- to_bgp->name_pretty);
+ zlog_debug("%s: updating RD %pRD, %pFX to vrf %s", __func__,
+ prd, p, to_bgp->name_pretty);
/* shallow copy */
static_attr = *path_vpn->attr;
@@ -1525,6 +1925,8 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
ecommunity_free(&old_ecom);
}
+ community_strip_accept_own(&static_attr);
+
/*
* Nexthop: stash and clear
*
@@ -1651,9 +2053,16 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
/*
* For VRF-2-VRF route-leaking,
* the source will be the originating VRF.
+ *
+ * If ACCEPT_OWN mechanism is enabled, then we SHOULD(?)
+ * get the source VRF (BGP) by looking at the RD.
*/
+ struct bgp *src_bgp = bgp_lookup_by_rd(path_vpn, prd, afi);
+
if (path_vpn->extra && path_vpn->extra->bgp_orig)
src_vrf = path_vpn->extra->bgp_orig;
+ else if (src_bgp)
+ src_vrf = src_bgp;
else
src_vrf = from_bgp;
@@ -1663,8 +2072,9 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *to_bgp, /* to */
return true;
}
-bool vpn_leak_to_vrf_update(struct bgp *from_bgp, /* from */
- struct bgp_path_info *path_vpn) /* route */
+bool vpn_leak_to_vrf_update(struct bgp *from_bgp,
+ struct bgp_path_info *path_vpn,
+ struct prefix_rd *prd)
{
struct listnode *mnode, *mnnode;
struct bgp *bgp;
@@ -1681,7 +2091,7 @@ bool vpn_leak_to_vrf_update(struct bgp *from_bgp, /* from */
if (!path_vpn->extra
|| path_vpn->extra->bgp_orig != bgp) { /* no loop */
leak_success |= vpn_leak_to_vrf_update_onevrf(
- bgp, from_bgp, path_vpn);
+ bgp, from_bgp, path_vpn, prd);
}
}
return leak_success;
@@ -1837,7 +2247,7 @@ void vpn_leak_to_vrf_update_all(struct bgp *to_bgp, struct bgp *vpn_from,
continue;
vpn_leak_to_vrf_update_onevrf(to_bgp, vpn_from,
- bpi);
+ bpi, NULL);
}
}
}
diff --git a/bgpd/bgp_mplsvpn.h b/bgpd/bgp_mplsvpn.h
index c5cc7d429..7b57e4c75 100644
--- a/bgpd/bgp_mplsvpn.h
+++ b/bgpd/bgp_mplsvpn.h
@@ -41,6 +41,8 @@
#define V4_HEADER_OVERLAY \
" Network Next Hop EthTag Overlay Index RouterMac\n"
+#define BGP_PREFIX_SID_SRV6_MAX_FUNCTION_LENGTH 20
+
extern void bgp_mplsvpn_init(void);
extern int bgp_nlri_parse_vpn(struct peer *, struct attr *, struct bgp_nlri *);
extern uint32_t decode_label(mpls_label_t *);
@@ -70,7 +72,8 @@ extern void vpn_leak_to_vrf_update_all(struct bgp *to_bgp, struct bgp *from_bgp,
afi_t afi);
extern bool vpn_leak_to_vrf_update(struct bgp *from_bgp,
- struct bgp_path_info *path_vpn);
+ struct bgp_path_info *path_vpn,
+ struct prefix_rd *prd);
extern void vpn_leak_to_vrf_withdraw(struct bgp *from_bgp,
struct bgp_path_info *path_vpn);
@@ -78,9 +81,20 @@ extern void vpn_leak_to_vrf_withdraw(struct bgp *from_bgp,
extern void vpn_leak_zebra_vrf_label_update(struct bgp *bgp, afi_t afi);
extern void vpn_leak_zebra_vrf_label_withdraw(struct bgp *bgp, afi_t afi);
extern void vpn_leak_zebra_vrf_sid_update(struct bgp *bgp, afi_t afi);
+extern void vpn_leak_zebra_vrf_sid_update_per_af(struct bgp *bgp, afi_t afi);
+extern void vpn_leak_zebra_vrf_sid_update_per_vrf(struct bgp *bgp);
extern void vpn_leak_zebra_vrf_sid_withdraw(struct bgp *bgp, afi_t afi);
+extern void vpn_leak_zebra_vrf_sid_withdraw_per_af(struct bgp *bgp, afi_t afi);
+extern void vpn_leak_zebra_vrf_sid_withdraw_per_vrf(struct bgp *bgp);
extern int vpn_leak_label_callback(mpls_label_t label, void *lblid, bool alloc);
extern void ensure_vrf_tovpn_sid(struct bgp *vpn, struct bgp *vrf, afi_t afi);
+extern void delete_vrf_tovpn_sid(struct bgp *vpn, struct bgp *vrf, afi_t afi);
+extern void delete_vrf_tovpn_sid_per_af(struct bgp *vpn, struct bgp *vrf,
+ afi_t afi);
+extern void delete_vrf_tovpn_sid_per_vrf(struct bgp *vpn, struct bgp *vrf);
+extern void ensure_vrf_tovpn_sid_per_af(struct bgp *vpn, struct bgp *vrf,
+ afi_t afi);
+extern void ensure_vrf_tovpn_sid_per_vrf(struct bgp *vpn, struct bgp *vrf);
extern void transpose_sid(struct in6_addr *sid, uint32_t label, uint8_t offset,
uint8_t size);
extern void vrf_import_from_vrf(struct bgp *to_bgp, struct bgp *from_bgp,
@@ -248,17 +262,33 @@ static inline void vpn_leak_postchange(enum vpn_policy_direction direction,
vpn_leak_zebra_vrf_label_update(bgp_vrf, afi);
}
- if (!bgp_vrf->vpn_policy[afi].tovpn_sid)
+ if (bgp_vrf->vpn_policy[afi].tovpn_sid_index == 0 &&
+ !CHECK_FLAG(bgp_vrf->vpn_policy[afi].flags,
+ BGP_VPN_POLICY_TOVPN_SID_AUTO) &&
+ bgp_vrf->tovpn_sid_index == 0 &&
+ !CHECK_FLAG(bgp_vrf->vrf_flags, BGP_VRF_TOVPN_SID_AUTO))
+ delete_vrf_tovpn_sid(bgp_vpn, bgp_vrf, afi);
+
+ if (!bgp_vrf->vpn_policy[afi].tovpn_sid && !bgp_vrf->tovpn_sid)
ensure_vrf_tovpn_sid(bgp_vpn, bgp_vrf, afi);
- if (!bgp_vrf->vpn_policy[afi].tovpn_sid
- && bgp_vrf->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent)
+ if ((!bgp_vrf->vpn_policy[afi].tovpn_sid &&
+ bgp_vrf->vpn_policy[afi].tovpn_zebra_vrf_sid_last_sent) ||
+ (!bgp_vrf->tovpn_sid &&
+ bgp_vrf->tovpn_zebra_vrf_sid_last_sent))
vpn_leak_zebra_vrf_sid_withdraw(bgp_vrf, afi);
- if (sid_diff(bgp_vrf->vpn_policy[afi].tovpn_sid,
- bgp_vrf->vpn_policy[afi]
- .tovpn_zebra_vrf_sid_last_sent)) {
- vpn_leak_zebra_vrf_sid_update(bgp_vrf, afi);
+ if (bgp_vrf->vpn_policy[afi].tovpn_sid) {
+ if (sid_diff(bgp_vrf->vpn_policy[afi].tovpn_sid,
+ bgp_vrf->vpn_policy[afi]
+ .tovpn_zebra_vrf_sid_last_sent)) {
+ vpn_leak_zebra_vrf_sid_update(bgp_vrf, afi);
+ }
+ } else if (bgp_vrf->tovpn_sid) {
+ if (sid_diff(bgp_vrf->tovpn_sid,
+ bgp_vrf->tovpn_zebra_vrf_sid_last_sent)) {
+ vpn_leak_zebra_vrf_sid_update(bgp_vrf, afi);
+ }
}
vpn_leak_from_vrf_update_all(bgp_vpn, bgp_vrf, afi);
diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c
index 9ecc2ae4e..9582ec01e 100644
--- a/bgpd/bgp_network.c
+++ b/bgpd/bgp_network.c
@@ -207,6 +207,25 @@ int bgp_md5_set(struct peer *peer)
return bgp_md5_set_password(peer, peer->password);
}
+static void bgp_update_setsockopt_tcp_keepalive(struct bgp *bgp, int fd)
+{
+ if (!bgp)
+ return;
+ if (bgp->tcp_keepalive_idle != 0) {
+ int ret;
+
+ ret = setsockopt_tcp_keepalive(fd, bgp->tcp_keepalive_idle,
+ bgp->tcp_keepalive_intvl,
+ bgp->tcp_keepalive_probes);
+ if (ret < 0)
+ zlog_err(
+ "Can't set TCP keepalive on socket %d, idle %u intvl %u probes %u",
+ fd, bgp->tcp_keepalive_idle,
+ bgp->tcp_keepalive_intvl,
+ bgp->tcp_keepalive_probes);
+ }
+}
+
int bgp_md5_unset(struct peer *peer)
{
/* Unset the password from listen socket. */
@@ -415,6 +434,9 @@ static void bgp_accept(struct thread *thread)
bgp_socket_set_buffer_size(bgp_sock);
+ /* Set TCP keepalive when TCP keepalive is enabled */
+ bgp_update_setsockopt_tcp_keepalive(bgp, bgp_sock);
+
/* Check remote IP address */
peer1 = peer_lookup(bgp, &su);
@@ -718,12 +740,16 @@ int bgp_connect(struct peer *peer)
bgp_socket_set_buffer_size(peer->fd);
+ /* Set TCP keepalive when TCP keepalive is enabled */
+ bgp_update_setsockopt_tcp_keepalive(peer->bgp, peer->fd);
+
if (bgp_set_socket_ttl(peer, peer->fd) < 0) {
peer->last_reset = PEER_DOWN_SOCKET_ERROR;
if (bgp_debug_neighbor_events(peer))
zlog_debug("%s: Failure to set socket ttl for connection to %s, error received: %s(%d)",
__func__, peer->host, safe_strerror(errno),
errno);
+
return -1;
}
diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c
index 7274bcdb2..fd1aa6ab4 100644
--- a/bgpd/bgp_nht.c
+++ b/bgpd/bgp_nht.c
@@ -139,7 +139,8 @@ static int bgp_isvalid_nexthop_for_mpls(struct bgp_nexthop_cache *bnc,
*/
return (bgp_zebra_num_connects() == 0 ||
(bnc && (bnc->nexthop_num > 0 &&
- (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID) ||
+ (CHECK_FLAG(path->flags, BGP_PATH_ACCEPT_OWN) ||
+ CHECK_FLAG(bnc->flags, BGP_NEXTHOP_LABELED_VALID) ||
bnc->bgp->srv6_enabled ||
bgp_isvalid_nexthop_for_ebgp(bnc, path) ||
bgp_isvalid_nexthop_for_mplsovergre(bnc, path)))));
@@ -1389,14 +1390,21 @@ static uint32_t bgp_l3nhg_start;
static void bgp_l3nhg_add_cb(const char *name)
{
}
+
+static void bgp_l3nhg_modify_cb(const struct nexthop_group_cmd *nhgc)
+{
+}
+
static void bgp_l3nhg_add_nexthop_cb(const struct nexthop_group_cmd *nhgc,
const struct nexthop *nhop)
{
}
+
static void bgp_l3nhg_del_nexthop_cb(const struct nexthop_group_cmd *nhgc,
const struct nexthop *nhop)
{
}
+
static void bgp_l3nhg_del_cb(const char *name)
{
}
@@ -1409,8 +1417,9 @@ static void bgp_l3nhg_zebra_init(void)
bgp_l3nhg_zebra_inited = true;
bgp_l3nhg_start = zclient_get_nhg_start(ZEBRA_ROUTE_BGP);
- nexthop_group_init(bgp_l3nhg_add_cb, bgp_l3nhg_add_nexthop_cb,
- bgp_l3nhg_del_nexthop_cb, bgp_l3nhg_del_cb);
+ nexthop_group_init(bgp_l3nhg_add_cb, bgp_l3nhg_modify_cb,
+ bgp_l3nhg_add_nexthop_cb, bgp_l3nhg_del_nexthop_cb,
+ bgp_l3nhg_del_cb);
}
diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c
index d1667fac2..c8cb6b77e 100644
--- a/bgpd/bgp_open.c
+++ b/bgpd/bgp_open.c
@@ -357,6 +357,7 @@ static void bgp_capability_orf_not_support(struct peer *peer, iana_afi_t afi,
}
static const struct message orf_type_str[] = {
+ {ORF_TYPE_RESERVED, "Reserved"},
{ORF_TYPE_PREFIX, "Prefixlist"},
{ORF_TYPE_PREFIX_OLD, "Prefixlist (old)"},
{0}};
@@ -433,6 +434,12 @@ static int bgp_capability_orf_entry(struct peer *peer,
switch (hdr->code) {
case CAPABILITY_CODE_ORF:
switch (type) {
+ case ORF_TYPE_RESERVED:
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug(
+ "%s Addr-family %d/%d has reserved ORF type, ignoring",
+ peer->host, afi, safi);
+ break;
case ORF_TYPE_PREFIX:
break;
default:
@@ -443,6 +450,12 @@ static int bgp_capability_orf_entry(struct peer *peer,
break;
case CAPABILITY_CODE_ORF_OLD:
switch (type) {
+ case ORF_TYPE_RESERVED:
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug(
+ "%s Addr-family %d/%d has reserved ORF type, ignoring",
+ peer->host, afi, safi);
+ break;
case ORF_TYPE_PREFIX_OLD:
break;
default:
diff --git a/bgpd/bgp_open.h b/bgpd/bgp_open.h
index 19ddd9bd2..6be94443c 100644
--- a/bgpd/bgp_open.h
+++ b/bgpd/bgp_open.h
@@ -76,6 +76,7 @@ struct graceful_restart_af {
/* Cooperative Route Filtering Capability. */
/* ORF Type */
+#define ORF_TYPE_RESERVED 0
#define ORF_TYPE_PREFIX 64
#define ORF_TYPE_PREFIX_OLD 128
diff --git a/bgpd/bgp_orr.c b/bgpd/bgp_orr.c
new file mode 100644
index 000000000..7fed6b775
--- /dev/null
+++ b/bgpd/bgp_orr.c
@@ -0,0 +1,1176 @@
+/*
+ * BGP Optimal Route Reflection
+ * Copyright (C) 2021 Samsung R&D Institute India - Bangalore.
+ * Madhurilatha Kuruganti
+ *
+ * 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 "bgpd/bgpd.h"
+#include "bgpd/bgp_debug.h"
+#include "bgpd/bgp_orr.h"
+#include "bgpd/bgp_vty.h"
+#include "zclient.h"
+
+DEFINE_MTYPE_STATIC(BGPD, ORR_IGP_INFO, "ORR IGP Metric info");
+
+static inline bool is_orr_primary_root(struct bgp_orr_group *orr_group,
+ char *host)
+{
+ return orr_group->primary && strmatch(orr_group->primary->host, host);
+}
+
+static inline bool is_orr_secondary_root(struct bgp_orr_group *orr_group,
+ char *host)
+{
+ return orr_group->secondary &&
+ strmatch(orr_group->secondary->host, host);
+}
+
+static inline bool is_orr_tertiary_root(struct bgp_orr_group *orr_group,
+ char *host)
+{
+ return orr_group->tertiary && strmatch(orr_group->tertiary->host, host);
+}
+
+static inline bool is_orr_active_root(struct bgp_orr_group *orr_group,
+ char *host)
+{
+ return orr_group->active && strmatch(orr_group->active->host, host);
+}
+
+static inline bool is_orr_root_node(struct bgp_orr_group *orr_group, char *host)
+{
+ return is_orr_primary_root(orr_group, host) ||
+ is_orr_secondary_root(orr_group, host) ||
+ is_orr_tertiary_root(orr_group, host);
+}
+
+static inline bool is_peer_orr_group_member(struct peer *peer, afi_t afi,
+ safi_t safi, const char *name)
+{
+ return peer_af_flag_check(peer, afi, safi, PEER_FLAG_ORR_GROUP) &&
+ strmatch(peer->orr_group_name[afi][safi], name);
+}
+
+static inline bool is_peer_reachable(struct peer *peer, afi_t afi, safi_t safi)
+{
+ return peer && peer->afc_nego[afi][safi] && peer_established(peer);
+}
+
+static inline bool is_peer_active_eligible(struct peer *peer, afi_t afi,
+ safi_t safi, const char *name)
+{
+ return is_peer_reachable(peer, afi, safi) &&
+ is_peer_orr_group_member(peer, afi, safi, name);
+}
+
+static void bgp_orr_igp_metric_register(struct bgp_orr_group *orr_group,
+ bool reg);
+
+static void
+bgp_peer_update_orr_group_active_root(struct peer *peer, afi_t afi, safi_t safi,
+ struct bgp_orr_group *orr_group);
+
+static struct bgp_orr_group *bgp_orr_group_new(struct bgp *bgp, afi_t afi,
+ safi_t safi, const char *name)
+{
+ int ret;
+ struct list *orr_group_list = NULL;
+ struct bgp_orr_group *orr_group = NULL;
+
+ assert(bgp && name);
+
+ if (!bgp->orr_group[afi][safi])
+ bgp->orr_group[afi][safi] = list_new();
+
+ orr_group_list = bgp->orr_group[afi][safi];
+ orr_group = XCALLOC(MTYPE_BGP_ORR_GROUP, sizeof(struct bgp_orr_group));
+
+ listnode_add(orr_group_list, orr_group);
+
+ orr_group->name = XSTRDUP(MTYPE_BGP_ORR_GROUP_NAME, name);
+ orr_group->afi = afi;
+ orr_group->safi = safi;
+ orr_group->primary = orr_group->secondary = orr_group->tertiary = NULL;
+ orr_group->bgp = bgp;
+
+ /* Initialize ORR Group route table */
+ orr_group->route_table = bgp_table_init(bgp, afi, safi);
+ assert(orr_group->route_table);
+
+ /*
+ * Register for opaque messages from IGPs when first ORR group is
+ * configured.
+ */
+ if (!bgp->orr_group_count) {
+ ret = zclient_register_opaque(zclient, ORR_IGP_METRIC_UPDATE);
+ if (ret != ZCLIENT_SEND_SUCCESS)
+ bgp_orr_debug(
+ "%s: zclient_register_opaque failed with ret = %d",
+ __func__, ret);
+ }
+
+ bgp->orr_group_count++;
+
+ return orr_group;
+}
+
+static void bgp_orr_group_free(struct bgp_orr_group *orr_group)
+{
+ afi_t afi;
+ safi_t safi;
+ struct bgp *bgp;
+
+ assert(orr_group && orr_group->bgp && orr_group->name);
+
+ bgp_orr_debug("%s: Deleting ORR group %s", __func__, orr_group->name);
+
+ afi = orr_group->afi;
+ safi = orr_group->safi;
+ bgp = orr_group->bgp;
+
+ /*
+ * Unregister with IGP for metric calculation from specified location
+ * and delete igp_metric_info calculated for this group
+ */
+ bgp_orr_igp_metric_register(orr_group, false);
+
+ /* Free RR client list associated with this ORR group */
+ if (orr_group->rr_client_list)
+ list_delete(&orr_group->rr_client_list);
+
+ /* Free route table */
+ bgp_table_unlock(orr_group->route_table);
+ orr_group->route_table = NULL;
+
+ /* Unset ORR Group parameters */
+ XFREE(MTYPE_BGP_ORR_GROUP_NAME, orr_group->name);
+
+ listnode_delete(bgp->orr_group[afi][safi], orr_group);
+ XFREE(MTYPE_BGP_ORR_GROUP, orr_group);
+
+ bgp->orr_group_count--;
+
+ if (!bgp->orr_group[afi][safi]->count)
+ list_delete(&bgp->orr_group[afi][safi]);
+}
+
+struct bgp_orr_group *bgp_orr_group_lookup_by_name(struct bgp *bgp, afi_t afi,
+ safi_t safi,
+ const char *name)
+{
+ struct list *orr_group_list = NULL;
+ struct bgp_orr_group *group = NULL;
+ struct listnode *node;
+
+ assert(bgp);
+
+ orr_group_list = bgp->orr_group[afi][safi];
+ if (!orr_group_list)
+ return NULL;
+
+ for (ALL_LIST_ELEMENTS_RO(orr_group_list, node, group))
+ if (strmatch(group->name, name))
+ return group;
+
+ bgp_orr_debug("%s: For %s, ORR Group '%s' not found.", __func__,
+ get_afi_safi_str(afi, safi, false), name);
+
+ return NULL;
+}
+
+static char *bgp_orr_group_rrclient_lookup(struct bgp_orr_group *orr_group,
+ const char *rr_client_host)
+{
+ char *rrclient = NULL;
+ struct list *orr_group_rrclient_list = NULL;
+ struct listnode *node;
+
+ orr_group_rrclient_list = orr_group->rr_client_list;
+ if (!orr_group_rrclient_list)
+ return NULL;
+
+ for (ALL_LIST_ELEMENTS_RO(orr_group_rrclient_list, node, rrclient))
+ if (strmatch(rrclient, rr_client_host))
+ return rrclient;
+
+ bgp_orr_debug(
+ "%s: For %s, %s not found in ORR Group '%s' RR Client list",
+ __func__,
+ get_afi_safi_str(orr_group->afi, orr_group->safi, false),
+ rr_client_host, orr_group->name);
+
+ return NULL;
+}
+
+static void bgp_orr_group_rrclient_update(struct peer *peer, afi_t afi,
+ safi_t safi,
+ const char *orr_group_name, bool add)
+{
+ char *rr_client = NULL;
+ struct bgp_orr_group *orr_group = NULL;
+ struct list *rr_client_list = NULL;
+
+ assert(peer && peer->bgp && orr_group_name);
+
+ /* Get BGP ORR entry for the given address-family */
+ orr_group = bgp_orr_group_lookup_by_name(peer->bgp, afi, safi,
+ orr_group_name);
+ if (!orr_group) {
+ bgp_orr_debug("%s: For %s, ORR Group '%s' not found.", __func__,
+ get_afi_safi_str(afi, safi, false),
+ orr_group_name);
+ return;
+ }
+
+ /* Get BGP ORR client entry for the given RR client */
+ rr_client = bgp_orr_group_rrclient_lookup(orr_group, peer->host);
+
+ /* Nothing to do */
+ if ((rr_client && add) || (!rr_client && !add))
+ return;
+
+ if (add) {
+ /* Create BGP ORR RR client entry to the ORR Group */
+ if (!orr_group->rr_client_list)
+ orr_group->rr_client_list = list_new();
+ rr_client_list = orr_group->rr_client_list;
+ rr_client = XSTRDUP(MTYPE_BGP_PEER_HOST, peer->host);
+
+ listnode_add(rr_client_list, rr_client);
+
+ bgp_orr_debug(
+ "%s: For %s, %pBP is added to ORR Group '%s' RR Client list.",
+ __func__, get_afi_safi_str(afi, safi, false), peer,
+ orr_group_name);
+ } else {
+ /* Delete BGP ORR RR client entry from the ORR Group */
+ listnode_delete(orr_group->rr_client_list, rr_client);
+ XFREE(MTYPE_BGP_PEER_HOST, rr_client);
+ if (!orr_group->rr_client_list->count)
+ list_delete(&orr_group->rr_client_list);
+
+ bgp_orr_debug(
+ "%s: For %s, %pBP is removed from ORR Group '%s' RR Client list.",
+ __func__, get_afi_safi_str(afi, safi, false), peer,
+ orr_group_name);
+ }
+}
+
+/* Create/Update BGP Optimal Route Reflection Group */
+int bgp_afi_safi_orr_group_set(struct bgp *bgp, afi_t afi, safi_t safi,
+ const char *name, struct peer *primary,
+ struct peer *secondary, struct peer *tertiary)
+{
+ bool primary_eligible = false;
+ bool secondary_eligible = false;
+ bool tertiary_eligible = false;
+ struct bgp_orr_group *orr_group = NULL;
+
+ bgp_orr_debug(
+ "%s: For %s, ORR Group '%s' Primary %pBP Secondary %pBP Tertiary %pBP",
+ __func__, get_afi_safi_str(afi, safi, false), name, primary,
+ secondary, tertiary);
+
+ /* Get BGP ORR entry for the given address-family */
+ orr_group = bgp_orr_group_lookup_by_name(bgp, afi, safi, name);
+ if (!orr_group) {
+ /* Create BGP ORR entry for the given address-family */
+ orr_group = bgp_orr_group_new(bgp, afi, safi, name);
+ }
+
+ /* Compare and update Primary Root Address */
+ if (primary) {
+ if (!orr_group->primary ||
+ !strmatch(orr_group->primary->host, primary->host))
+ orr_group->primary = primary;
+ else
+ bgp_orr_debug("%s: No change in Primary Root",
+ __func__);
+
+ /*
+ * Update Active Root if there is a change and primary is
+ * reachable.
+ */
+ primary_eligible =
+ is_peer_active_eligible(primary, afi, safi, name);
+ if (!orr_group->active) {
+ orr_group->active = primary;
+ bgp_orr_igp_metric_register(orr_group, true);
+ } else if (orr_group->primary &&
+ !strmatch(orr_group->active->host,
+ orr_group->primary->host)) {
+ bgp_orr_igp_metric_register(orr_group, false);
+ orr_group->active = primary;
+ bgp_orr_igp_metric_register(orr_group, true);
+ } else
+ bgp_orr_debug("%s: %s", __func__,
+ orr_group->primary
+ ? "No change in Active Root"
+ : "Primary Root is NULL");
+ } else {
+ if (orr_group->primary) {
+ if (orr_group->active &&
+ strmatch(orr_group->active->host,
+ orr_group->primary->host)) {
+ bgp_orr_igp_metric_register(orr_group, false);
+
+ orr_group->active = NULL;
+ }
+ orr_group->primary = NULL;
+ }
+ }
+
+ /* Compare and update Secondary Root Address */
+ if (secondary) {
+ if (!orr_group->secondary ||
+ !strmatch(orr_group->secondary->host, secondary->host))
+ orr_group->secondary = secondary;
+ else
+ bgp_orr_debug("%s: No change in Secondary Root",
+ __func__);
+
+ /* Update Active Root if Primary is not reachable */
+ secondary_eligible =
+ is_peer_active_eligible(secondary, afi, safi, name);
+ if (!orr_group->active) {
+ orr_group->active = secondary;
+ bgp_orr_igp_metric_register(orr_group, true);
+ } else if (!primary_eligible && orr_group->secondary &&
+ !strmatch(orr_group->active->host,
+ orr_group->secondary->host)) {
+ bgp_orr_igp_metric_register(orr_group, false);
+ orr_group->active = secondary;
+ bgp_orr_igp_metric_register(orr_group, true);
+ } else
+ bgp_orr_debug(
+ "%s: %s", __func__,
+ primary_eligible
+ ? "Primary is Active Root"
+ : orr_group->secondary
+ ? "No change in Active Root"
+ : "Secondary Root is NULL");
+ } else {
+ if (orr_group->secondary) {
+ if (orr_group->active &&
+ strmatch(orr_group->active->host,
+ orr_group->secondary->host)) {
+ bgp_orr_igp_metric_register(orr_group, false);
+
+ orr_group->active = NULL;
+ }
+ orr_group->secondary = NULL;
+ }
+ }
+
+ /* Compare and update Tertiary Root Address */
+ if (tertiary) {
+ if (!orr_group->tertiary ||
+ !strmatch(orr_group->tertiary->host, tertiary->host))
+ orr_group->tertiary = tertiary;
+ else
+ bgp_orr_debug("%s: No change in Tertiay Root",
+ __func__);
+
+ /*
+ * Update Active Root if Primary & Secondary are not reachable
+ */
+ tertiary_eligible =
+ is_peer_active_eligible(tertiary, afi, safi, name);
+ if (!orr_group->active) {
+ orr_group->active = tertiary;
+ bgp_orr_igp_metric_register(orr_group, true);
+ } else if (!primary_eligible && !secondary_eligible &&
+ orr_group->tertiary &&
+ !strmatch(orr_group->active->host,
+ orr_group->tertiary->host)) {
+ bgp_orr_igp_metric_register(orr_group, false);
+
+ orr_group->active = tertiary;
+ bgp_orr_igp_metric_register(orr_group, true);
+ } else
+ bgp_orr_debug(
+ "%s: %s", __func__,
+ primary_eligible
+ ? "Primary is Active Root"
+ : secondary_eligible
+ ? "Secondary is Active Root"
+ : !orr_group->tertiary
+ ? "Tertiary Root is NULL"
+ : "No change in Active Root");
+ } else {
+ if (orr_group->tertiary) {
+ if (orr_group->active &&
+ strmatch(orr_group->active->host,
+ orr_group->tertiary->host)) {
+ bgp_orr_igp_metric_register(orr_group, false);
+
+ orr_group->active = NULL;
+ }
+ orr_group->tertiary = NULL;
+ }
+ }
+
+ if (orr_group->active && !primary_eligible && !secondary_eligible &&
+ !tertiary_eligible) {
+ bgp_orr_igp_metric_register(orr_group, false);
+
+ orr_group->active = NULL;
+ }
+
+ bgp_orr_debug("%s: For %s, ORR Group '%s' Active Root is %pBP",
+ __func__, get_afi_safi_str(afi, safi, false), name,
+ orr_group->active);
+
+ return CMD_SUCCESS;
+}
+
+/* Delete BGP Optimal Route Reflection Group */
+int bgp_afi_safi_orr_group_unset(struct bgp *bgp, afi_t afi, safi_t safi,
+ const char *name)
+{
+ struct bgp_orr_group *orr_group;
+
+ orr_group = bgp_orr_group_lookup_by_name(bgp, afi, safi, name);
+ if (!orr_group)
+ return CMD_WARNING;
+
+ /* Check if there are any neighbors configured with this ORR Group */
+ if (orr_group->rr_client_list) {
+ bgp_orr_debug(
+ "%s: For %s, ORR Group '%s' not removed as '%s' is configured on neighbor(s)",
+ __func__,
+ get_afi_safi_str(orr_group->afi, orr_group->safi,
+ false),
+ name, name);
+ return CMD_WARNING;
+ }
+
+ bgp_orr_group_free(orr_group);
+ return CMD_SUCCESS;
+}
+
+/* Set optimal route reflection group to the peer */
+static int peer_orr_group_set(struct peer *peer, afi_t afi, safi_t safi,
+ const char *orr_group_name)
+{
+ struct bgp_orr_group *orr_group = NULL;
+
+ if (!peer)
+ return CMD_WARNING;
+
+ /* Get BGP ORR entry for the given address-family */
+ orr_group = bgp_orr_group_lookup_by_name(peer->bgp, afi, safi,
+ orr_group_name);
+ if (!orr_group) {
+ /* Create BGP ORR entry for the given address-family */
+ orr_group =
+ bgp_orr_group_new(peer->bgp, afi, safi, orr_group_name);
+ }
+
+ /* Skip processing if there is no change in ORR Group */
+ if (peer_af_flag_check(peer, afi, safi, PEER_FLAG_ORR_GROUP)) {
+ if (strmatch(peer->orr_group_name[afi][safi], orr_group_name)) {
+ bgp_orr_debug(
+ "%s: For %s, ORR Group '%s' is already configured on %pBP",
+ __func__, get_afi_safi_str(afi, safi, false),
+ orr_group_name, peer);
+ return CMD_SUCCESS;
+ }
+ /* Remove the peer from ORR Group's peer list */
+ bgp_orr_group_rrclient_update(peer, afi, safi,
+ peer->orr_group_name[afi][safi],
+ false);
+ XFREE(MTYPE_BGP_ORR_GROUP_NAME,
+ peer->orr_group_name[afi][safi]);
+ }
+
+ peer->orr_group_name[afi][safi] =
+ XSTRDUP(MTYPE_BGP_ORR_GROUP_NAME, orr_group_name);
+ SET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_ORR_GROUP);
+
+ /* Add the peer to ORR Group's client list */
+ bgp_orr_group_rrclient_update(peer, afi, safi, orr_group_name, true);
+
+ /* Update ORR group active root and register with IGP */
+ bgp_peer_update_orr_group_active_root(peer, afi, safi, orr_group);
+
+ return CMD_SUCCESS;
+}
+
+/* Unset optimal route reflection group from the peer*/
+int peer_orr_group_unset(struct peer *peer, afi_t afi, safi_t safi,
+ const char *orr_group_name)
+{
+ struct bgp_orr_group *orr_group = NULL;
+
+ assert(peer && peer->bgp && orr_group_name);
+
+ if (!peer_af_flag_check(peer, afi, safi, PEER_FLAG_ORR_GROUP) ||
+ !strmatch(peer->orr_group_name[afi][safi], orr_group_name)) {
+ bgp_orr_debug(
+ "%s: For %s, ORR Group '%s' is not configured on %pBP",
+ __func__, get_afi_safi_str(afi, safi, false),
+ orr_group_name, peer);
+ return CMD_ERR_NO_MATCH;
+ }
+
+ /* Check if this RR Client is one of the root nodes */
+ orr_group = bgp_orr_group_lookup_by_name(peer->bgp, afi, safi,
+ orr_group_name);
+
+ /* Should not be Null when orr-group is enabled on peer */
+ assert(orr_group);
+
+ /* Check if the peer is one of the root nodes of the ORR group */
+ if (is_orr_root_node(orr_group, peer->host))
+ return CMD_WARNING;
+
+ /* Remove the peer from ORR Group's client list */
+ bgp_orr_group_rrclient_update(peer, afi, safi, orr_group_name, false);
+
+ /* Update ORR group active root and unregister with IGP */
+ bgp_peer_update_orr_group_active_root(peer, afi, safi, orr_group);
+
+ UNSET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_ORR_GROUP);
+ XFREE(MTYPE_BGP_ORR_GROUP_NAME, peer->orr_group_name[afi][safi]);
+
+ return CMD_SUCCESS;
+}
+
+int bgp_afi_safi_orr_group_set_vty(struct vty *vty, afi_t afi, safi_t safi,
+ const char *name, const char *primary_str,
+ const char *secondary_str,
+ const char *tertiary_str, bool unset)
+{
+ int ret = CMD_WARNING_CONFIG_FAILED;
+ struct bgp *bgp;
+ struct peer *primary = NULL, *secondary = NULL, *tertiary = NULL;
+
+ bgp = bgp_get_default();
+ if (!bgp) {
+ vty_out(vty, "%% No BGP process is configured\n");
+ return ret;
+ }
+
+ if (unset) {
+ ret = bgp_afi_safi_orr_group_unset(bgp, afi, safi, name);
+ if (ret != CMD_SUCCESS)
+ vty_out(vty,
+ "%% ORR Group %s not removed as '%s' is not found OR configured on neighbor(s)\n",
+ name, name);
+ return ret;
+ }
+
+ primary = peer_and_group_lookup_vty(vty, primary_str);
+ if (!primary || !peer_af_flag_check(primary, afi, safi,
+ PEER_FLAG_REFLECTOR_CLIENT)) {
+ vty_out(vty,
+ "%% Primary Root is not a Route Reflector Client\n");
+ return ret;
+ }
+
+ if (secondary_str) {
+ secondary = peer_and_group_lookup_vty(vty, secondary_str);
+ if (!secondary ||
+ !peer_af_flag_check(secondary, afi, safi,
+ PEER_FLAG_REFLECTOR_CLIENT)) {
+ vty_out(vty,
+ "%% Secondary Root is not a Route Reflector Client\n");
+ return ret;
+ }
+ }
+
+ if (tertiary_str) {
+ tertiary = peer_and_group_lookup_vty(vty, tertiary_str);
+ if (!tertiary ||
+ !peer_af_flag_check(tertiary, afi, safi,
+ PEER_FLAG_REFLECTOR_CLIENT)) {
+ vty_out(vty,
+ "%% Tertiary Root is not a Route Reflector Client\n");
+ return ret;
+ }
+ }
+ return bgp_afi_safi_orr_group_set(bgp, afi, safi, name, primary,
+ secondary, tertiary);
+}
+
+/* Set optimal route reflection group name to the peer. */
+int peer_orr_group_set_vty(struct vty *vty, const char *ip_str, afi_t afi,
+ safi_t safi, const char *orr_group_name, bool unset)
+{
+ int ret = CMD_WARNING_CONFIG_FAILED;
+ struct peer *peer;
+
+ peer = peer_and_group_lookup_vty(vty, ip_str);
+ if (!peer)
+ return ret;
+
+ if (!peer_af_flag_check(peer, afi, safi, PEER_FLAG_REFLECTOR_CLIENT)) {
+ vty_out(vty, "%% Neighbor %s is not a Route Reflector Client\n",
+ peer->host);
+ return ret;
+ }
+
+ if (!unset) {
+ ret = peer_orr_group_set(peer, afi, safi, orr_group_name);
+ if (ret != CMD_SUCCESS)
+ vty_out(vty, "%% ORR Group '%s' is not configured\n",
+ orr_group_name);
+ } else {
+ ret = peer_orr_group_unset(peer, afi, safi, orr_group_name);
+ if (ret == CMD_ERR_NO_MATCH)
+ vty_out(vty,
+ "%% ORR Group '%s' is not configured on %s\n",
+ orr_group_name, peer->host);
+ else if (ret == CMD_WARNING)
+ vty_out(vty,
+ "%% %s is one of the root nodes of ORR Group '%s'.\n",
+ peer->host, orr_group_name);
+ }
+ return bgp_vty_return(vty, ret);
+}
+
+void bgp_config_write_orr(struct vty *vty, struct bgp *bgp, afi_t afi,
+ safi_t safi)
+{
+ struct list *orr_group_list;
+ struct listnode *node;
+ struct bgp_orr_group *orr_group;
+
+ orr_group_list = bgp->orr_group[afi][safi];
+ if (!orr_group_list)
+ return;
+
+ for (ALL_LIST_ELEMENTS_RO(orr_group_list, node, orr_group)) {
+ /* optimal route reflection configuration */
+ vty_out(vty, " optimal-route-reflection %s", orr_group->name);
+ if (orr_group->primary)
+ vty_out(vty, " %s", orr_group->primary->host);
+ if (orr_group->secondary)
+ vty_out(vty, " %s", orr_group->secondary->host);
+ if (orr_group->tertiary)
+ vty_out(vty, " %s", orr_group->tertiary->host);
+ vty_out(vty, "\n");
+ }
+}
+
+static void bgp_show_orr_group(struct vty *vty, struct bgp_orr_group *orr_group,
+ afi_t afi, safi_t safi)
+{
+ char *rrclient = NULL;
+ struct listnode *node;
+ struct bgp_orr_igp_metric *igp_metric = NULL;
+ struct list *orr_group_rrclient_list = NULL;
+ struct list *orr_group_igp_metric_info = NULL;
+
+ if (!orr_group)
+ return;
+
+ vty_out(vty, "\nORR group: %s, %s\n", orr_group->name,
+ get_afi_safi_str(afi, safi, false));
+ vty_out(vty, "Configured root:");
+ vty_out(vty, " primary: %pBP,", orr_group->primary);
+ vty_out(vty, " secondary: %pBP,", orr_group->secondary);
+ vty_out(vty, " tertiary: %pBP\n", orr_group->tertiary);
+ vty_out(vty, "Active Root: %pBP\n", orr_group->active);
+
+ orr_group_rrclient_list = orr_group->rr_client_list;
+ if (!orr_group_rrclient_list)
+ return;
+
+ vty_out(vty, "\nRR Clients mapped:\n");
+
+ for (ALL_LIST_ELEMENTS_RO(orr_group_rrclient_list, node, rrclient))
+ vty_out(vty, "%s\n", rrclient);
+
+ vty_out(vty, "\nNumber of mapping entries: %d\n\n",
+ orr_group_rrclient_list->count);
+
+
+ orr_group_igp_metric_info = orr_group->igp_metric_info;
+ if (!orr_group_igp_metric_info)
+ return;
+ vty_out(vty, "Prefix\t\t\t\t\t\tCost\n");
+ for (ALL_LIST_ELEMENTS_RO(orr_group_igp_metric_info, node,
+ igp_metric)) {
+ vty_out(vty, "%pFX\t\t\t\t\t\t%d\n", &igp_metric->prefix,
+ igp_metric->igp_metric);
+ }
+ vty_out(vty, "\nNumber of mapping entries: %d\n\n",
+ orr_group_igp_metric_info->count);
+}
+
+int bgp_show_orr(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi,
+ const char *orr_group_name, uint8_t show_flags)
+{
+ struct listnode *node;
+ struct bgp_orr_group *orr_group = NULL;
+ struct list *orr_group_list = NULL;
+ int ret = 0;
+
+ assert(bgp);
+
+ /* Display the matching entries for the given ORR Group */
+ if (orr_group_name) {
+ orr_group = bgp_orr_group_lookup_by_name(bgp, afi, safi,
+ orr_group_name);
+ if (!orr_group) {
+ vty_out(vty, "%% ORR Group %s not found\n",
+ orr_group_name);
+ return CMD_WARNING;
+ }
+ bgp_show_orr_group(vty, orr_group, afi, safi);
+ return ret;
+ }
+ orr_group_list = bgp->orr_group[afi][safi];
+ if (!orr_group_list)
+ return ret;
+
+ for (ALL_LIST_ELEMENTS_RO(orr_group_list, node, orr_group))
+ bgp_show_orr_group(vty, orr_group, afi, safi);
+
+ return ret;
+}
+
+/* Check if the Route Reflector Client belongs to any ORR Group */
+bool peer_orr_rrclient_check(struct peer *peer, afi_t afi, safi_t safi)
+{
+ char *rrclient = NULL;
+ struct listnode *node;
+ struct list *orr_group_list = NULL;
+ struct list *orr_group_rrclient_list = NULL;
+ struct bgp_orr_group *orr_group = NULL;
+
+ assert(peer && peer->bgp);
+
+ orr_group_list = peer->bgp->orr_group[afi][safi];
+ if (!orr_group_list)
+ return false;
+
+ for (ALL_LIST_ELEMENTS_RO(orr_group_list, node, orr_group)) {
+ /* Check if peer configured as primary/secondary/tertiary root
+ */
+ if (is_orr_root_node(orr_group, peer->host))
+ return true;
+ /*
+ * Check if peer is mapped to any ORR Group in this
+ * Address Family.
+ */
+ orr_group_rrclient_list = orr_group->rr_client_list;
+ if (!orr_group_rrclient_list)
+ continue;
+
+ for (ALL_LIST_ELEMENTS_RO(orr_group_rrclient_list, node,
+ rrclient))
+ if (strmatch(rrclient, peer->host))
+ return true;
+ }
+ return false;
+}
+
+static void
+bgp_peer_update_orr_group_active_root(struct peer *peer, afi_t afi, safi_t safi,
+ struct bgp_orr_group *orr_group)
+{
+ assert(peer && orr_group);
+
+ /* Nothing to do if this peer is not one of the root nodes */
+ if (!is_orr_root_node(orr_group, peer->host))
+ return;
+
+ /* Root is reachable and group member, update Active Root if needed */
+ if (is_peer_active_eligible(peer, afi, safi, orr_group->name)) {
+ /* Nothing to do, if this is the current Active Root */
+ if (is_orr_active_root(orr_group, peer->host))
+ return;
+
+ /* If Active is null, update this node as Active Root */
+ if (!orr_group->active) {
+ orr_group->active = peer;
+ bgp_orr_igp_metric_register(orr_group, true);
+ return;
+ }
+
+ /* If this is Primary and current Active is not Primary */
+ if (is_orr_primary_root(orr_group, peer->host)) {
+ bgp_orr_igp_metric_register(orr_group, false);
+ orr_group->active = peer;
+ bgp_orr_igp_metric_register(orr_group, true);
+ return;
+ }
+
+ /*
+ * If this is Secondary and current Active is not
+ * Primary/Secondary
+ */
+ if (is_orr_secondary_root(orr_group, peer->host)) {
+ if (is_orr_active_root(orr_group,
+ orr_group->primary->host))
+ return;
+ bgp_orr_igp_metric_register(orr_group, false);
+ orr_group->active = peer;
+ bgp_orr_igp_metric_register(orr_group, true);
+ return;
+ }
+ return;
+ }
+
+ /* Non Active Root is unreachable, so nothing to do */
+ if (!is_orr_active_root(orr_group, peer->host))
+ return;
+
+ if (is_orr_primary_root(orr_group, peer->host)) {
+ /* If secondary is reachable, update it as Active */
+ if (is_peer_active_eligible(orr_group->secondary, afi, safi,
+ orr_group->name)) {
+ bgp_orr_igp_metric_register(orr_group, false);
+
+ orr_group->active = orr_group->secondary;
+ bgp_orr_igp_metric_register(orr_group, true);
+ return;
+ }
+
+ /* If tertiary is reachable, update it as Active */
+ if (is_peer_active_eligible(orr_group->tertiary, afi, safi,
+ orr_group->name)) {
+ bgp_orr_igp_metric_register(orr_group, false);
+
+ orr_group->active = orr_group->tertiary;
+ bgp_orr_igp_metric_register(orr_group, true);
+ return;
+ }
+ } else {
+ if (is_orr_secondary_root(orr_group, peer->host)) {
+ /* If tertiary is reachable, update it as Active */
+ if (is_peer_active_eligible(orr_group->tertiary, afi,
+ safi, orr_group->name)) {
+ bgp_orr_igp_metric_register(orr_group, false);
+
+ orr_group->active = orr_group->tertiary;
+ bgp_orr_igp_metric_register(orr_group, true);
+ return;
+ }
+ }
+ }
+
+ /* Assign Active as null */
+ bgp_orr_igp_metric_register(orr_group, false);
+ orr_group->active = NULL;
+
+ bgp_orr_debug("%s: For %s, ORR Group '%s' has no active root", __func__,
+ get_afi_safi_str(afi, safi, false),
+ peer->orr_group_name[afi][safi]);
+}
+
+void bgp_peer_update_orr_active_roots(struct peer *peer)
+{
+ afi_t afi;
+ safi_t safi;
+ struct bgp_orr_group *orr_group;
+
+ assert(peer && peer->bgp);
+
+ FOREACH_AFI_SAFI (afi, safi) {
+ if (!peer->orr_group_name[afi][safi])
+ continue;
+
+ /* Get BGP ORR entry for the given address-family */
+ orr_group = bgp_orr_group_lookup_by_name(
+ peer->bgp, afi, safi, peer->orr_group_name[afi][safi]);
+ assert(orr_group);
+
+ /* Free ORR related memory. */
+ if (peer->status != Deleted) {
+ bgp_peer_update_orr_group_active_root(peer, afi, safi,
+ orr_group);
+ continue;
+ }
+
+ if (!is_orr_root_node(orr_group, peer->host)) {
+ peer_orr_group_unset(peer, afi, safi,
+ peer->orr_group_name[afi][safi]);
+ continue;
+ }
+
+ if (is_orr_primary_root(orr_group, peer->host)) {
+ orr_group->primary = orr_group->secondary;
+ orr_group->secondary = orr_group->tertiary;
+ } else if (is_orr_secondary_root(orr_group, peer->host))
+ orr_group->secondary = orr_group->tertiary;
+ orr_group->tertiary = NULL;
+
+ bgp_afi_safi_orr_group_set(peer->bgp, afi, safi,
+ orr_group->name, orr_group->primary,
+ orr_group->secondary,
+ orr_group->tertiary);
+ peer_orr_group_unset(peer, afi, safi,
+ peer->orr_group_name[afi][safi]);
+ }
+}
+
+/* IGP metric calculated from Active Root */
+static int bgp_orr_igp_metric_update(struct orr_igp_metric_info *table)
+{
+ afi_t afi;
+ safi_t safi;
+ bool add = false;
+ bool root_found = false;
+ uint32_t instId = 0;
+ uint32_t numEntries = 0;
+ uint32_t entry = 0;
+ uint8_t proto = ZEBRA_ROUTE_MAX;
+ struct bgp *bgp = NULL;
+ struct prefix pfx, root = {0};
+
+ struct list *orr_group_list = NULL;
+ struct bgp_orr_group *group = NULL;
+ struct listnode *node, *nnode;
+
+ struct bgp_orr_igp_metric *igp_metric = NULL;
+ struct list *bgp_orr_igp_metric = NULL;
+
+ bgp = bgp_get_default();
+ assert(bgp && table);
+
+ proto = table->proto;
+ afi = family2afi(table->root.family);
+ safi = table->safi;
+ instId = table->instId;
+ add = table->add;
+ numEntries = table->num_entries;
+ prefix_copy(&root, &table->root);
+
+ if ((proto != ZEBRA_ROUTE_OSPF) && (proto != ZEBRA_ROUTE_OSPF6) &&
+ (proto != ZEBRA_ROUTE_ISIS)) {
+ bgp_orr_debug("%s: Message received from unsupported protocol",
+ __func__);
+ return -1;
+ }
+
+ orr_group_list = bgp->orr_group[afi][safi];
+ if (!orr_group_list) {
+ bgp_orr_debug(
+ "%s: Address family %s has no ORR Groups configured",
+ __func__, get_afi_safi_str(afi, safi, false));
+ return -1;
+ }
+
+ if (BGP_DEBUG(optimal_route_reflection, ORR)) {
+ zlog_debug(
+ "[BGP-ORR] %s: Received metric update from protocol %s instance %d",
+ __func__,
+ proto == ZEBRA_ROUTE_ISIS
+ ? "ISIS"
+ : (proto == ZEBRA_ROUTE_OSPF ? "OSPF"
+ : "OSPF6"),
+ instId);
+ zlog_debug("[BGP-ORR] %s: Address family %s", __func__,
+ get_afi_safi_str(afi, safi, false));
+ zlog_debug("[BGP-ORR] %s: Root %pFX", __func__, &root);
+ zlog_debug("[BGP-ORR] %s: Number of entries to be %s %d",
+ __func__, add ? "added" : "deleted", numEntries);
+ zlog_debug("[BGP-ORR] %s: Prefix (Cost) :", __func__);
+ for (entry = 0; entry < numEntries; entry++)
+ zlog_debug("[BGP-ORR] %s: %pFX (%d)", __func__,
+ &table->nexthop[entry].prefix,
+ table->nexthop[entry].metric);
+ }
+ /*
+ * Update IGP metric info of all ORR Groups having this as active root
+ */
+ for (ALL_LIST_ELEMENTS_RO(orr_group_list, node, group)) {
+ if (str2prefix(group->active->host, &pfx) == 0) {
+ bgp_orr_debug("%s: Malformed prefix for %pBP", __func__,
+ group->active);
+ continue;
+ }
+ /*
+ * Copy IGP info if root matches with the active root of the
+ * group
+ */
+ if (prefix_cmp(&pfx, &root) == 0) {
+ if (add) {
+ /* Add new routes */
+ if (!group->igp_metric_info)
+ group->igp_metric_info = list_new();
+
+ bgp_orr_igp_metric = group->igp_metric_info;
+ if (!bgp_orr_igp_metric)
+ bgp_orr_igp_metric_register(group,
+ false);
+ assert(bgp_orr_igp_metric);
+
+ for (entry = 0; entry < numEntries; entry++) {
+ igp_metric = XCALLOC(
+ MTYPE_ORR_IGP_INFO,
+ sizeof(struct
+ bgp_orr_igp_metric));
+ if (!igp_metric)
+ bgp_orr_igp_metric_register(
+ group, false);
+
+ prefix_copy(
+ &igp_metric->prefix,
+ &table->nexthop[entry].prefix);
+ igp_metric->igp_metric =
+ table->nexthop[entry].metric;
+ listnode_add(bgp_orr_igp_metric,
+ igp_metric);
+ }
+ } else {
+ /* Delete old routes */
+ for (entry = 0; entry < numEntries; entry++) {
+ for (ALL_LIST_ELEMENTS(
+ group->igp_metric_info,
+ node, nnode, igp_metric)) {
+ if (prefix_cmp(
+ &igp_metric->prefix,
+ &table->nexthop[entry]
+ .prefix))
+ continue;
+ listnode_delete(
+ group->igp_metric_info,
+ igp_metric);
+ XFREE(MTYPE_ORR_IGP_INFO,
+ igp_metric);
+ }
+ }
+ }
+ root_found = true;
+ break;
+ }
+ }
+ /* Received IGP for root node thats not found in ORR active roots */
+ if (!root_found) {
+ bgp_orr_debug(
+ "%s: Received IGP SPF information for root %pFX which is not an ORR active root",
+ __func__, &root);
+ }
+ assert(root_found);
+ return 0;
+}
+
+/* Register with IGP for sending SPF info */
+static void bgp_orr_igp_metric_register(struct bgp_orr_group *orr_group,
+ bool reg)
+{
+ int ret;
+ struct orr_igp_metric_reg msg;
+ struct prefix p;
+ char *rr_client = NULL;
+
+ assert(orr_group);
+
+ if (!orr_group->active)
+ return;
+
+ memset(&msg, 0, sizeof(msg));
+ ret = str2prefix(orr_group->active->host, &p);
+
+ /* Malformed prefix */
+ assert(ret);
+
+ /* Check if the active root is part of this ORR group */
+ rr_client = bgp_orr_group_rrclient_lookup(orr_group,
+ orr_group->active->host);
+ if (reg && !rr_client) {
+ bgp_orr_debug(
+ "%s: active root %pBP is not part of this ORR group",
+ __func__, orr_group->active);
+ return;
+ }
+
+ msg.reg = reg;
+ msg.proto = ZEBRA_ROUTE_BGP;
+ msg.safi = orr_group->safi;
+ prefix_copy(&msg.prefix, &p);
+ strlcpy(msg.group_name, orr_group->name, sizeof(msg.group_name));
+
+ bgp_orr_debug(
+ "%s: %s with IGP for metric calculation from location %pFX",
+ __func__, reg ? "Register" : "Unregister", &msg.prefix);
+
+ if (zclient_send_opaque(zclient, ORR_IGP_METRIC_REGISTER,
+ (uint8_t *)&msg,
+ sizeof(msg)) == ZCLIENT_SEND_FAILURE)
+ zlog_warn("[BGP-ORR] %s: Failed to send message to IGP.",
+ __func__);
+
+ /* Free IGP metric info calculated from previous active location */
+ if (!reg && orr_group->igp_metric_info)
+ list_delete(&orr_group->igp_metric_info);
+}
+
+/* BGP ORR message processing */
+int bgg_orr_message_process(enum bgp_orr_msg_type msg_type, void *msg)
+{
+ int ret = 0;
+
+ assert(msg && msg_type > BGP_ORR_IMSG_INVALID &&
+ msg_type < BGP_ORR_IMSG_MAX);
+ switch (msg_type) {
+ case BGP_ORR_IMSG_GROUP_CREATE:
+ break;
+ case BGP_ORR_IMSG_GROUP_DELETE:
+ break;
+ case BGP_ORR_IMSG_GROUP_UPDATE:
+ break;
+ case BGP_ORR_IMSG_SET_ORR_ON_PEER:
+ break;
+ case BGP_ORR_IMSG_UNSET_ORR_ON_PEER:
+ break;
+ case BGP_ORR_IMSG_IGP_METRIC_UPDATE:
+ ret = bgp_orr_igp_metric_update(
+ (struct orr_igp_metric_info *)msg);
+ break;
+ case BGP_ORR_IMSG_SHOW_ORR:
+ /* bgp_show_orr */
+ break;
+ case BGP_ORR_IMSG_SHOW_ORR_GROUP:
+ /* bgp_show_orr_group */
+ break;
+ default:
+ break;
+ }
+
+ /* Free Memory */
+ return ret;
+}
+
+/*
+ * Cleanup ORR information - invoked at the time of bgpd exit or
+ * when the BGP instance (default) is being freed.
+ */
+void bgp_orr_cleanup(struct bgp *bgp)
+{
+ afi_t afi;
+ safi_t safi;
+ struct listnode *node, *nnode;
+ struct bgp_orr_group *orr_group;
+
+ assert(bgp);
+
+ if (!bgp->orr_group_count)
+ return;
+
+ FOREACH_AFI_SAFI (afi, safi) {
+ for (ALL_LIST_ELEMENTS(bgp->orr_group[afi][safi], node, nnode,
+ orr_group))
+ bgp_orr_group_free(orr_group);
+ }
+}
diff --git a/bgpd/bgp_orr.h b/bgpd/bgp_orr.h
new file mode 100644
index 000000000..158de3034
--- /dev/null
+++ b/bgpd/bgp_orr.h
@@ -0,0 +1,102 @@
+/*
+ * BGP Optimal Route Reflection
+ * Copyright (C) 2021 Samsung R&D Institute India - Bangalore.
+ * Madhurilatha Kuruganti
+ *
+ * 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_BGP_ORR_H
+#define _FRR_BGP_ORR_H
+#include <zebra.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Macro to log debug message */
+#define bgp_orr_debug(...) \
+ do { \
+ if (BGP_DEBUG(optimal_route_reflection, ORR)) \
+ zlog_debug("[BGP-ORR] " __VA_ARGS__); \
+ } while (0)
+
+
+/* BGP ORR Message Type */
+enum bgp_orr_msg_type {
+ BGP_ORR_IMSG_INVALID = 0,
+
+ /* ORR group update */
+ BGP_ORR_IMSG_GROUP_CREATE = 1,
+ BGP_ORR_IMSG_GROUP_DELETE,
+ BGP_ORR_IMSG_GROUP_UPDATE,
+
+ /* ORR group update on a BGP RR Client */
+ BGP_ORR_IMSG_SET_ORR_ON_PEER = 4,
+ BGP_ORR_IMSG_UNSET_ORR_ON_PEER,
+
+ /* ORR IGP Metric Update from IGP from requested Location */
+ BGP_ORR_IMSG_IGP_METRIC_UPDATE = 6,
+
+ /* ORR Group Related Information display */
+ BGP_ORR_IMSG_SHOW_ORR = 7,
+ BGP_ORR_IMSG_SHOW_ORR_GROUP,
+
+ /* Invalid Message Type*/
+ BGP_ORR_IMSG_MAX
+};
+
+extern struct zclient *zclient;
+
+extern void bgp_config_write_orr(struct vty *vty, struct bgp *bgp, afi_t afi,
+ safi_t safi);
+
+extern int bgp_afi_safi_orr_group_set_vty(struct vty *vty, afi_t afi,
+ safi_t safi, const char *name,
+ const char *primary_str,
+ const char *secondary_str,
+ const char *tertiary_str, bool unset);
+extern int peer_orr_group_unset(struct peer *peer, afi_t afi, safi_t safi,
+ const char *orr_group_name);
+extern int peer_orr_group_set_vty(struct vty *vty, const char *ip_str,
+ afi_t afi, safi_t safi,
+ const char *orr_group_name, bool unset);
+extern bool peer_orr_rrclient_check(struct peer *peer, afi_t afi, safi_t safi);
+
+extern int bgp_show_orr(struct vty *vty, struct bgp *bgp, afi_t afi,
+ safi_t safi, const char *orr_group_name,
+ uint8_t show_flags);
+
+extern int bgp_afi_safi_orr_group_set(struct bgp *bgp, afi_t afi, safi_t safi,
+ const char *name, struct peer *primary,
+ struct peer *secondary,
+ struct peer *tertiary);
+extern int bgp_afi_safi_orr_group_unset(struct bgp *bgp, afi_t afi, safi_t safi,
+ const char *name);
+
+extern void bgp_peer_update_orr_active_roots(struct peer *peer);
+
+extern int bgg_orr_message_process(enum bgp_orr_msg_type msg_type, void *msg);
+
+extern struct bgp_orr_group *bgp_orr_group_lookup_by_name(struct bgp *bgp,
+ afi_t afi,
+ safi_t safi,
+ const char *name);
+extern void bgp_orr_cleanup(struct bgp *bgp);
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FRR_BGP_ORR_H */
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index 8ae31bf2e..f3ca3bba0 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -124,6 +124,7 @@ static void bgp_packet_add(struct peer *peer, struct stream *s)
{
intmax_t delta;
uint32_t holdtime;
+ intmax_t sendholdtime;
frr_with_mutex (&peer->io_mtx) {
/* if the queue is empty, reset the "last OK" timestamp to
@@ -136,8 +137,14 @@ static void bgp_packet_add(struct peer *peer, struct stream *s)
stream_fifo_push(peer->obuf, s);
delta = monotime(NULL) - peer->last_sendq_ok;
- holdtime = atomic_load_explicit(&peer->holdtime,
- memory_order_relaxed);
+
+ if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER))
+ holdtime = atomic_load_explicit(&peer->holdtime,
+ memory_order_relaxed);
+ else
+ holdtime = peer->bgp->default_holdtime;
+
+ sendholdtime = holdtime * 2;
/* Note that when we're here, we're adding some packet to the
* OutQ. That includes keepalives when there is nothing to
@@ -149,18 +156,18 @@ static void bgp_packet_add(struct peer *peer, struct stream *s)
*/
if (!holdtime) {
/* no holdtime, do nothing. */
- } else if (delta > 2 * (intmax_t)holdtime) {
+ } else if (delta > sendholdtime) {
flog_err(
EC_BGP_SENDQ_STUCK_PROPER,
- "%s has not made any SendQ progress for 2 holdtimes, terminating session",
- peer->host);
+ "%pBP has not made any SendQ progress for 2 holdtimes (%jds), terminating session",
+ peer, sendholdtime);
BGP_EVENT_ADD(peer, TCP_fatal_error);
} else if (delta > (intmax_t)holdtime &&
monotime(NULL) - peer->last_sendq_warn > 5) {
flog_warn(
EC_BGP_SENDQ_STUCK_WARN,
- "%s has not made any SendQ progress for 1 holdtime, peer overloaded?",
- peer->host);
+ "%pBP has not made any SendQ progress for 1 holdtime (%us), peer overloaded?",
+ peer, holdtime);
peer->last_sendq_warn = monotime(NULL);
}
}
@@ -1004,9 +1011,12 @@ static void bgp_notify_send_internal(struct peer *peer, uint8_t code,
if (code == BGP_NOTIFY_CEASE) {
if (sub_code == BGP_NOTIFY_CEASE_ADMIN_RESET)
peer->last_reset = PEER_DOWN_USER_RESET;
- else if (sub_code == BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN)
- peer->last_reset = PEER_DOWN_USER_SHUTDOWN;
- else
+ else if (sub_code == BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN) {
+ if (CHECK_FLAG(peer->sflags, PEER_STATUS_RTT_SHUTDOWN))
+ peer->last_reset = PEER_DOWN_RTT_SHUTDOWN;
+ else
+ peer->last_reset = PEER_DOWN_USER_SHUTDOWN;
+ } else
peer->last_reset = PEER_DOWN_NOTIFY_SEND;
} else
peer->last_reset = PEER_DOWN_NOTIFY_SEND;
@@ -1379,8 +1389,27 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size)
|| CHECK_FLAG(peer->flags, PEER_FLAG_EXTENDED_OPT_PARAMS)) {
uint8_t opttype;
+ if (STREAM_READABLE(peer->curr) < 1) {
+ flog_err(
+ EC_BGP_PKT_OPEN,
+ "%s: stream does not have enough bytes for extended optional parameters",
+ peer->host);
+ bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR,
+ BGP_NOTIFY_OPEN_MALFORMED_ATTR);
+ return BGP_Stop;
+ }
+
opttype = stream_getc(peer->curr);
if (opttype == BGP_OPEN_NON_EXT_OPT_TYPE_EXTENDED_LENGTH) {
+ if (STREAM_READABLE(peer->curr) < 2) {
+ flog_err(
+ EC_BGP_PKT_OPEN,
+ "%s: stream does not have enough bytes to read the extended optional parameters optlen",
+ peer->host);
+ bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR,
+ BGP_NOTIFY_OPEN_MALFORMED_ATTR);
+ return BGP_Stop;
+ }
optlen = stream_getw(peer->curr);
SET_FLAG(peer->sflags,
PEER_STATUS_EXT_OPT_PARAMS_LENGTH);
@@ -1723,15 +1752,24 @@ static int bgp_keepalive_receive(struct peer *peer, bgp_size_t size)
/* If the peer's RTT is higher than expected, shutdown
* the peer automatically.
*/
- if (CHECK_FLAG(peer->flags, PEER_FLAG_RTT_SHUTDOWN)
- && peer->rtt > peer->rtt_expected) {
+ if (!CHECK_FLAG(peer->flags, PEER_FLAG_RTT_SHUTDOWN))
+ return Receive_KEEPALIVE_message;
+ if (peer->rtt > peer->rtt_expected) {
peer->rtt_keepalive_rcv++;
if (peer->rtt_keepalive_rcv > peer->rtt_keepalive_conf) {
- zlog_warn(
- "%s shutdown due to high round-trip-time (%dms > %dms)",
- peer->host, peer->rtt, peer->rtt_expected);
+ char rtt_shutdown_reason[BUFSIZ] = {};
+
+ snprintfrr(
+ rtt_shutdown_reason,
+ sizeof(rtt_shutdown_reason),
+ "shutdown due to high round-trip-time (%dms > %dms, hit %u times)",
+ peer->rtt, peer->rtt_expected,
+ peer->rtt_keepalive_rcv);
+ zlog_warn("%s %s", peer->host, rtt_shutdown_reason);
+ SET_FLAG(peer->sflags, PEER_STATUS_RTT_SHUTDOWN);
+ peer_tx_shutdown_message_set(peer, rtt_shutdown_reason);
peer_flag_set(peer, PEER_FLAG_SHUTDOWN);
}
} else {
diff --git a/bgpd/bgp_pbr.c b/bgpd/bgp_pbr.c
index 7b5e28724..b71e19ab3 100644
--- a/bgpd/bgp_pbr.c
+++ b/bgpd/bgp_pbr.c
@@ -2074,6 +2074,9 @@ static void bgp_pbr_icmp_action(struct bgp *bgp, struct bgp_path_info *path,
bgp, path, bpf);
}
}
+
+ bpf->src_port = NULL;
+ bpf->dst_port = NULL;
}
static void bgp_pbr_policyroute_remove_from_zebra_recursive(
diff --git a/bgpd/bgp_regex.h b/bgpd/bgp_regex.h
index 43ebb9ac9..e07b7f911 100644
--- a/bgpd/bgp_regex.h
+++ b/bgpd/bgp_regex.h
@@ -18,19 +18,24 @@
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#ifndef _QUAGGA_BGP_REGEX_H
-#define _QUAGGA_BGP_REGEX_H
+#ifndef _FRR_BGP_REGEX_H
+#define _FRR_BGP_REGEX_H
#include <zebra.h>
-#ifdef HAVE_LIBPCREPOSIX
+#ifdef HAVE_LIBPCRE2_POSIX
+#ifndef _FRR_PCRE2_POSIX
+#define _FRR_PCRE2_POSIX
+#include <pcre2posix.h>
+#endif /* _FRR_PCRE2_POSIX */
+#elif defined(HAVE_LIBPCREPOSIX)
#include <pcreposix.h>
#else
#include <regex.h>
-#endif /* HAVE_LIBPCREPOSIX */
+#endif /* HAVE_LIBPCRE2_POSIX */
extern void bgp_regex_free(regex_t *regex);
extern regex_t *bgp_regcomp(const char *str);
extern int bgp_regexec(regex_t *regex, struct aspath *aspath);
-#endif /* _QUAGGA_BGP_REGEX_H */
+#endif /* _FRR_BGP_REGEX_H */
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 61976834f..6eb1a556b 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -72,6 +72,7 @@
#include "bgpd/bgp_addpath.h"
#include "bgpd/bgp_mac.h"
#include "bgpd/bgp_network.h"
+#include "bgpd/bgp_orr.h"
#include "bgpd/bgp_trace.h"
#include "bgpd/bgp_rpki.h"
@@ -89,9 +90,7 @@
#include "bgpd/bgp_flowspec_util.h"
#include "bgpd/bgp_pbr.h"
-#ifndef VTYSH_EXTRACT_PL
#include "bgpd/bgp_route_clippy.c"
-#endif
DEFINE_HOOK(bgp_snmp_update_stats,
(struct bgp_node *rn, struct bgp_path_info *pi, bool added),
@@ -102,10 +101,6 @@ DEFINE_HOOK(bgp_rpki_prefix_status,
const struct prefix *prefix),
(peer, attr, prefix));
-/* Render dest to prefix_rd based on safi */
-static const struct prefix_rd *bgp_rd_from_dest(const struct bgp_dest *dest,
- safi_t safi);
-
/* Extern from bgp_dump.c */
extern const char *bgp_origin_str[];
extern const char *bgp_origin_long_str[];
@@ -567,6 +562,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
enum bgp_path_selection_reason *reason)
{
const struct prefix *new_p;
+ struct prefix exist_p;
struct attr *newattr, *existattr;
enum bgp_peer_sort new_sort;
enum bgp_peer_sort exist_sort;
@@ -599,6 +595,11 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
bool new_origin, exist_origin;
struct bgp_path_info *bpi_ultimate;
+ struct bgp_orr_group *orr_group = NULL;
+ struct listnode *node;
+ struct bgp_orr_igp_metric *igp_metric = NULL;
+ struct list *orr_group_igp_metric_info = NULL;
+
*paths_eq = 0;
/* 0. Null check. */
@@ -874,6 +875,79 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
return 0;
}
+ /* If a BGP speaker supports ACCEPT_OWN and is configured for the
+ * extensions defined in this document, the following step is inserted
+ * after the LOCAL_PREF comparison step in the BGP decision process:
+ * When comparing a pair of routes for a BGP destination, the
+ * route with the ACCEPT_OWN community attached is preferred over
+ * the route that does not have the community.
+ * This extra step MUST only be invoked during the best path selection
+ * process of VPN-IP routes.
+ */
+ if (safi == SAFI_MPLS_VPN &&
+ (CHECK_FLAG(new->peer->af_flags[afi][safi], PEER_FLAG_ACCEPT_OWN) ||
+ CHECK_FLAG(exist->peer->af_flags[afi][safi],
+ PEER_FLAG_ACCEPT_OWN))) {
+ bool new_accept_own = false;
+ bool exist_accept_own = false;
+ uint32_t accept_own = COMMUNITY_ACCEPT_OWN;
+
+ if (newattr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES))
+ new_accept_own = community_include(
+ bgp_attr_get_community(newattr), accept_own);
+ if (existattr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES))
+ exist_accept_own = community_include(
+ bgp_attr_get_community(existattr), accept_own);
+
+ if (new_accept_own && !exist_accept_own) {
+ *reason = bgp_path_selection_accept_own;
+ if (debug)
+ zlog_debug(
+ "%s: %s wins over %s due to accept-own",
+ pfx_buf, new_buf, exist_buf);
+ return 1;
+ }
+
+ if (!new_accept_own && exist_accept_own) {
+ *reason = bgp_path_selection_accept_own;
+ if (debug)
+ zlog_debug(
+ "%s: %s loses to %s due to accept-own",
+ pfx_buf, new_buf, exist_buf);
+ return 0;
+ }
+ }
+
+ /* Tie-breaker - AIGP (Metric TLV) attribute */
+ if (CHECK_FLAG(newattr->flag, ATTR_FLAG_BIT(BGP_ATTR_AIGP)) &&
+ CHECK_FLAG(existattr->flag, ATTR_FLAG_BIT(BGP_ATTR_AIGP)) &&
+ CHECK_FLAG(bgp->flags, BGP_FLAG_COMPARE_AIGP)) {
+ uint64_t new_aigp = bgp_attr_get_aigp_metric(newattr);
+ uint64_t exist_aigp = bgp_attr_get_aigp_metric(existattr);
+
+ if (new_aigp < exist_aigp) {
+ *reason = bgp_path_selection_aigp;
+ if (debug)
+ zlog_debug(
+ "%s: %s wins over %s due to AIGP %" PRIu64
+ " < %" PRIu64,
+ pfx_buf, new_buf, exist_buf, new_aigp,
+ exist_aigp);
+ return 1;
+ }
+
+ if (new_aigp > exist_aigp) {
+ *reason = bgp_path_selection_aigp;
+ if (debug)
+ zlog_debug(
+ "%s: %s loses to %s due to AIGP %" PRIu64
+ " > %" PRIu64,
+ pfx_buf, new_buf, exist_buf, new_aigp,
+ exist_aigp);
+ return 0;
+ }
+ }
+
/* 3. Local route check. We prefer:
* - BGP_ROUTE_STATIC
* - BGP_ROUTE_AGGREGATE
@@ -1061,6 +1135,49 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new,
if (exist->extra)
existm = exist->extra->igpmetric;
+ if (new->peer->orr_group_name[afi][safi]) {
+ ret = str2prefix(new->peer->host, &exist_p);
+ orr_group = bgp_orr_group_lookup_by_name(
+ bgp, afi, safi, new->peer->orr_group_name[afi][safi]);
+ if (orr_group) {
+ orr_group_igp_metric_info = orr_group->igp_metric_info;
+ if (orr_group_igp_metric_info) {
+ for (ALL_LIST_ELEMENTS_RO(
+ orr_group_igp_metric_info, node,
+ igp_metric)) {
+ if (ret &&
+ prefix_cmp(&exist_p,
+ &igp_metric->prefix) ==
+ 0) {
+ newm = igp_metric->igp_metric;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (exist->peer->orr_group_name[afi][safi]) {
+ ret = str2prefix(exist->peer->host, &exist_p);
+ orr_group = bgp_orr_group_lookup_by_name(
+ bgp, afi, safi, exist->peer->orr_group_name[afi][safi]);
+ if (orr_group) {
+ orr_group_igp_metric_info = orr_group->igp_metric_info;
+ if (orr_group_igp_metric_info) {
+ for (ALL_LIST_ELEMENTS_RO(
+ orr_group_igp_metric_info, node,
+ igp_metric)) {
+ if (ret &&
+ prefix_cmp(&exist_p,
+ &igp_metric->prefix) ==
+ 0) {
+ existm = igp_metric->igp_metric;
+ break;
+ }
+ }
+ }
+ }
+ }
+
if (newm < existm) {
if (debug && peer_sort_ret < 0)
zlog_debug(
@@ -2329,7 +2446,7 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
if (aspath_check_as_sets(attr->aspath))
return false;
- /* If neighbor sso is configured, then check if the route has
+ /* If neighbor soo is configured, then check if the route has
* SoO extended community and validate against the configured
* one. If they match, do not announce, to prevent routing
* loops.
@@ -2342,6 +2459,8 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
if ((ecommunity_lookup(ecomm, ECOMMUNITY_ENCODE_AS,
ECOMMUNITY_SITE_ORIGIN) ||
ecommunity_lookup(ecomm, ECOMMUNITY_ENCODE_AS4,
+ ECOMMUNITY_SITE_ORIGIN) ||
+ ecommunity_lookup(ecomm, ECOMMUNITY_ENCODE_IP,
ECOMMUNITY_SITE_ORIGIN)) &&
ecommunity_include(ecomm, ecomm_soo)) {
if (bgp_debug_update(NULL, p, subgrp->update_group, 0))
@@ -3833,6 +3952,60 @@ static void bgp_attr_add_no_export_community(struct attr *attr)
bgp_attr_set_community(attr, new);
}
+static bool bgp_accept_own(struct peer *peer, afi_t afi, safi_t safi,
+ struct attr *attr, const struct prefix *prefix,
+ int *sub_type)
+{
+ struct listnode *node, *nnode;
+ struct bgp *bgp;
+ bool accept_own_found = false;
+
+ if (safi != SAFI_MPLS_VPN)
+ return false;
+
+ /* Processing of the ACCEPT_OWN community is enabled by configuration */
+ if (!CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_ACCEPT_OWN))
+ return false;
+
+ /* The route in question carries the ACCEPT_OWN community */
+ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES)) {
+ struct community *comm = bgp_attr_get_community(attr);
+
+ if (community_include(comm, COMMUNITY_ACCEPT_OWN))
+ accept_own_found = true;
+ }
+
+ /* The route in question is targeted to one or more destination VRFs
+ * on the router (as determined by inspecting the Route Target(s)).
+ */
+ for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
+ if (bgp->inst_type != BGP_INSTANCE_TYPE_VRF)
+ continue;
+
+ if (accept_own_found &&
+ ecommunity_include(
+ bgp->vpn_policy[afi]
+ .rtlist[BGP_VPN_POLICY_DIR_TOVPN],
+ bgp_attr_get_ecommunity(attr))) {
+ if (bgp_debug_update(peer, prefix, NULL, 1))
+ zlog_debug(
+ "%pBP prefix %pFX has ORIGINATOR_ID, but it's accepted due to ACCEPT_OWN",
+ peer, prefix);
+
+ /* Treat this route as imported, because it's leaked
+ * already from another VRF, and we got an updated
+ * version from route-reflector with ACCEPT_OWN
+ * community.
+ */
+ *sub_type = BGP_ROUTE_IMPORTED;
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
struct attr *attr, afi_t afi, safi_t safi, int type,
int sub_type, struct prefix_rd *prd, mpls_label_t *label,
@@ -3854,11 +4027,10 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
int do_loop_check = 1;
int has_valid_label = 0;
afi_t nh_afi;
- uint8_t pi_type = 0;
- uint8_t pi_sub_type = 0;
bool force_evpn_import = false;
safi_t orig_safi = safi;
bool leak_success = true;
+ int allowas_in = 0;
if (frrtrace_enabled(frr_bgp, process_update)) {
char pfxprint[PREFIX2STR_BUFFER];
@@ -3872,6 +4044,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
int vnc_implicit_withdraw = 0;
#endif
int same_attr = 0;
+ const struct prefix *bgp_nht_param_prefix;
/* Special case for BGP-LU - map LU safi to ordinary unicast safi */
if (orig_safi == SAFI_LABELED_UNICAST)
@@ -3904,6 +4077,10 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
&& peer != bgp->peer_self)
bgp_adj_in_set(dest, peer, attr, addpath_id);
+ /* Update permitted loop count */
+ if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN))
+ allowas_in = peer->allowas_in[afi][safi];
+
/* Check previously received route. */
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next)
if (pi->peer == peer && pi->type == type
@@ -3913,8 +4090,8 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
/* AS path local-as loop check. */
if (peer->change_local_as) {
- if (peer->allowas_in[afi][safi])
- aspath_loop_count = peer->allowas_in[afi][safi];
+ if (allowas_in)
+ aspath_loop_count = allowas_in;
else if (!CHECK_FLAG(peer->flags,
PEER_FLAG_LOCAL_AS_NO_PREPEND))
aspath_loop_count = 1;
@@ -3935,25 +4112,37 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
if (aspath_get_last_as(attr->aspath) == bgp->as)
do_loop_check = 0;
+ if (CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_REFLECTOR_CLIENT))
+ bgp_nht_param_prefix = NULL;
+ else
+ bgp_nht_param_prefix = p;
+
/* AS path loop check. */
if (do_loop_check) {
- if (aspath_loop_check(attr->aspath, bgp->as)
- > peer->allowas_in[afi][safi]
- || (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION)
- && aspath_loop_check(attr->aspath, bgp->confed_id)
- > peer->allowas_in[afi][safi])) {
+ if (aspath_loop_check(attr->aspath, bgp->as) > allowas_in ||
+ (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION) &&
+ (aspath_loop_check(attr->aspath, bgp->confed_id) >
+ allowas_in))) {
peer->stat_pfx_aspath_loop++;
reason = "as-path contains our own AS;";
goto filtered;
}
}
- /* Route reflector originator ID check. */
+ /* Route reflector originator ID check. If ACCEPT_OWN mechanism is
+ * enabled, then take care of that too.
+ */
+ bool accept_own = false;
+
if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)
&& IPV4_ADDR_SAME(&bgp->router_id, &attr->originator_id)) {
- peer->stat_pfx_originator_loop++;
- reason = "originator is us;";
- goto filtered;
+ accept_own =
+ bgp_accept_own(peer, afi, safi, attr, p, &sub_type);
+ if (!accept_own) {
+ peer->stat_pfx_originator_loop++;
+ reason = "originator is us;";
+ goto filtered;
+ }
}
/* Route reflector cluster ID check. */
@@ -4059,15 +4248,10 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
bgp_attr_add_gshut_community(&new_attr);
}
- if (pi) {
- pi_type = pi->type;
- pi_sub_type = pi->sub_type;
- }
-
/* next hop check. */
- if (!CHECK_FLAG(peer->flags, PEER_FLAG_IS_RFAPI_HD)
- && bgp_update_martian_nexthop(bgp, afi, safi, pi_type, pi_sub_type,
- &new_attr, dest)) {
+ if (!CHECK_FLAG(peer->flags, PEER_FLAG_IS_RFAPI_HD) &&
+ bgp_update_martian_nexthop(bgp, afi, safi, type, sub_type,
+ &new_attr, dest)) {
peer->stat_pfx_nh_invalid++;
reason = "martian or self next-hop;";
bgp_attr_flush(&new_attr);
@@ -4443,8 +4627,8 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
if (bgp_find_or_add_nexthop(bgp, bgp_nexthop, nh_afi,
safi, pi, NULL, connected,
- p)
- || CHECK_FLAG(peer->flags, PEER_FLAG_IS_RFAPI_HD))
+ bgp_nht_param_prefix) ||
+ CHECK_FLAG(peer->flags, PEER_FLAG_IS_RFAPI_HD))
bgp_path_info_set_flag(dest, pi,
BGP_PATH_VALID);
else {
@@ -4456,8 +4640,13 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
bgp_path_info_unset_flag(dest, pi,
BGP_PATH_VALID);
}
- } else
+ } else {
+ if (accept_own)
+ bgp_path_info_set_flag(dest, pi,
+ BGP_PATH_ACCEPT_OWN);
+
bgp_path_info_set_flag(dest, pi, BGP_PATH_VALID);
+ }
#ifdef ENABLE_BGP_VNC
if (safi == SAFI_MPLS_VPN) {
@@ -4507,8 +4696,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
}
if ((SAFI_MPLS_VPN == safi)
&& (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
-
- leak_success = vpn_leak_to_vrf_update(bgp, pi);
+ leak_success = vpn_leak_to_vrf_update(bgp, pi, prd);
}
#ifdef ENABLE_BGP_VNC
@@ -4602,8 +4790,8 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
nh_afi = BGP_ATTR_NH_AFI(afi, new->attr);
if (bgp_find_or_add_nexthop(bgp, bgp, nh_afi, safi, new, NULL,
- connected, p)
- || CHECK_FLAG(peer->flags, PEER_FLAG_IS_RFAPI_HD))
+ connected, bgp_nht_param_prefix) ||
+ CHECK_FLAG(peer->flags, PEER_FLAG_IS_RFAPI_HD))
bgp_path_info_set_flag(dest, new, BGP_PATH_VALID);
else {
if (BGP_DEBUG(nht, NHT)) {
@@ -4616,8 +4804,12 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
}
bgp_path_info_unset_flag(dest, new, BGP_PATH_VALID);
}
- } else
+ } else {
+ if (accept_own)
+ bgp_path_info_set_flag(dest, new, BGP_PATH_ACCEPT_OWN);
+
bgp_path_info_set_flag(dest, new, BGP_PATH_VALID);
+ }
/* Addpath ID */
new->addpath_rx_id = addpath_id;
@@ -4663,7 +4855,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
}
if ((SAFI_MPLS_VPN == safi)
&& (bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT)) {
- leak_success = vpn_leak_to_vrf_update(bgp, new);
+ leak_success = vpn_leak_to_vrf_update(bgp, new, prd);
}
#ifdef ENABLE_BGP_VNC
if (SAFI_MPLS_VPN == safi) {
@@ -5156,7 +5348,10 @@ void bgp_soft_reconfig_table_task_cancel(const struct bgp *bgp,
}
}
-void bgp_soft_reconfig_in(struct peer *peer, afi_t afi, safi_t safi)
+/*
+ * Returns false if the peer is not configured for soft reconfig in
+ */
+bool bgp_soft_reconfig_in(struct peer *peer, afi_t afi, safi_t safi)
{
struct bgp_dest *dest;
struct bgp_table *table;
@@ -5164,14 +5359,14 @@ void bgp_soft_reconfig_in(struct peer *peer, afi_t afi, safi_t safi)
struct peer *npeer;
struct peer_af *paf;
- if (!peer_established(peer))
- return;
+ if (!CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG))
+ return false;
if ((safi != SAFI_MPLS_VPN) && (safi != SAFI_ENCAP)
&& (safi != SAFI_EVPN)) {
table = peer->bgp->rib[afi][safi];
if (!table)
- return;
+ return true;
table->soft_reconfig_init = true;
@@ -5231,6 +5426,8 @@ void bgp_soft_reconfig_in(struct peer *peer, afi_t afi, safi_t safi)
bgp_soft_reconfig_table(peer, afi, safi, table, &prd);
}
+
+ return true;
}
@@ -5983,6 +6180,9 @@ void bgp_static_update(struct bgp *bgp, const struct prefix *p,
if (afi == AFI_IP)
attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4;
+ if (bgp_static->igpmetric)
+ bgp_attr_set_aigp_metric(&attr, bgp_static->igpmetric);
+
if (bgp_static->atomic)
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_ATOMIC_AGGREGATE);
@@ -6384,7 +6584,8 @@ static void bgp_static_update_safi(struct bgp *bgp, const struct prefix *p,
if (SAFI_MPLS_VPN == safi
&& bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) {
- vpn_leak_to_vrf_update(bgp, pi);
+ vpn_leak_to_vrf_update(bgp, pi,
+ &bgp_static->prd);
}
#ifdef ENABLE_BGP_VNC
rfapiProcessUpdate(pi->peer, NULL, p, &bgp_static->prd,
@@ -6424,7 +6625,7 @@ static void bgp_static_update_safi(struct bgp *bgp, const struct prefix *p,
if (SAFI_MPLS_VPN == safi
&& bgp->inst_type == BGP_INSTANCE_TYPE_DEFAULT) {
- vpn_leak_to_vrf_update(bgp, new);
+ vpn_leak_to_vrf_update(bgp, new, &bgp_static->prd);
}
#ifdef ENABLE_BGP_VNC
rfapiProcessUpdate(new->peer, NULL, p, &bgp_static->prd, new->attr, afi,
@@ -8527,6 +8728,9 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
attr.flag |= ATTR_FLAG_BIT(BGP_ATTR_MULTI_EXIT_DISC);
attr.tag = tag;
+ if (metric)
+ bgp_attr_set_aigp_metric(&attr, metric);
+
afi = family2afi(p->family);
red = bgp_redist_lookup(bgp, afi, type, instance);
@@ -8536,8 +8740,10 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p,
/* Copy attribute for modification. */
attr_new = attr;
- if (red->redist_metric_flag)
+ if (red->redist_metric_flag) {
attr_new.med = red->redist_metric;
+ bgp_attr_set_aigp_metric(&attr_new, red->redist_metric);
+ }
/* Apply route-map. */
if (red->rmap.name) {
@@ -8783,8 +8989,12 @@ const char *bgp_path_selection_reason2str(enum bgp_path_selection_reason reason)
return "Weight";
case bgp_path_selection_local_pref:
return "Local Pref";
+ case bgp_path_selection_accept_own:
+ return "Accept Own";
case bgp_path_selection_local_route:
return "Local Route";
+ case bgp_path_selection_aigp:
+ return "AIGP";
case bgp_path_selection_confed_as_path:
return "Confederation based AS Path";
case bgp_path_selection_as_path:
@@ -8880,6 +9090,8 @@ static void route_vty_short_status_out(struct vty *vty,
vty_out(vty, "I");
else if (rpki_state == RPKI_NOTFOUND)
vty_out(vty, "N");
+ else
+ vty_out(vty, " ");
/* Route status display. */
if (CHECK_FLAG(path->flags, BGP_PATH_REMOVED))
@@ -10515,6 +10727,15 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
vty_out(vty, ", localpref %u", attr->local_pref);
}
+ if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_AIGP)) {
+ if (json_paths)
+ json_object_int_add(json_path, "aigpMetric",
+ bgp_attr_get_aigp_metric(attr));
+ else
+ vty_out(vty, ", aigp-metric %" PRIu64,
+ bgp_attr_get_aigp_metric(attr));
+ }
+
if (attr->weight != 0) {
if (json_paths)
json_object_int_add(json_path, "weight", attr->weight);
@@ -11858,8 +12079,8 @@ static void bgp_show_path_info(const struct prefix_rd *pfx_rd,
/*
* Return rd based on safi
*/
-static const struct prefix_rd *bgp_rd_from_dest(const struct bgp_dest *dest,
- safi_t safi)
+const struct prefix_rd *bgp_rd_from_dest(const struct bgp_dest *dest,
+ safi_t safi)
{
switch (safi) {
case SAFI_MPLS_VPN:
@@ -11868,7 +12089,6 @@ static const struct prefix_rd *bgp_rd_from_dest(const struct bgp_dest *dest,
return (struct prefix_rd *)(bgp_dest_get_prefix(dest));
default:
return NULL;
-
}
}
@@ -12202,8 +12422,10 @@ DEFUN (show_ip_bgp_large_community,
return CMD_WARNING;
if (argv_find(argv, argc, "AA:BB:CC", &idx)) {
- if (argv_find(argv, argc, "exact-match", &idx))
+ if (argv_find(argv, argc, "exact-match", &idx)) {
+ argc--;
exact_match = 1;
+ }
return bgp_show_lcommunity(vty, bgp, argc, argv,
exact_match, afi, safi, uj);
} else
@@ -12410,6 +12632,7 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
|alias ALIAS_NAME\
|A.B.C.D/M longer-prefixes\
|X:X::X:X/M longer-prefixes\
+ |optimal-route-reflection [WORD$orr_group_name]\
] [json$uj [detail$detail] | wide$wide]",
SHOW_STR IP_STR BGP_STR BGP_INSTANCE_HELP_STR BGP_AFI_HELP_STR
BGP_SAFI_WITH_LABEL_HELP_STR
@@ -12458,6 +12681,8 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
"Display route and more specific routes\n"
"IPv6 prefix\n"
"Display route and more specific routes\n"
+ "Display Optimal Route Reflection RR Clients\n"
+ "ORR Group name\n"
JSON_STR
"Display detailed version of JSON output\n"
"Increase table width for longer prefixes\n")
@@ -12474,6 +12699,7 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
uint16_t show_flags = 0;
enum rpki_states rpki_target_state = RPKI_NOT_BEING_USED;
struct prefix p;
+ bool orr_group = false;
if (uj) {
argc--;
@@ -12648,12 +12874,18 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
output_arg = &p;
}
+ if (argv_find(argv, argc, "optimal-route-reflection", &idx))
+ orr_group = true;
+
if (!all) {
/* show bgp: AFI_IP6, show ip bgp: AFI_IP */
if (community)
return bgp_show_community(vty, bgp, community,
exact_match, afi, safi,
show_flags);
+ else if (orr_group)
+ return bgp_show_orr(vty, bgp, afi, safi, orr_group_name,
+ show_flags);
else
return bgp_show(vty, bgp, afi, safi, sh_type,
output_arg, show_flags,
@@ -12699,6 +12931,11 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
vty, abgp, community,
exact_match, afi, safi,
show_flags);
+ else if (orr_group)
+ bgp_show_orr(vty, bgp, afi,
+ safi,
+ orr_group_name,
+ show_flags);
else
bgp_show(vty, abgp, afi, safi,
sh_type, output_arg,
@@ -12738,6 +12975,11 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd,
vty, abgp, community,
exact_match, afi, safi,
show_flags);
+ else if (orr_group)
+ bgp_show_orr(vty, bgp, afi,
+ safi,
+ orr_group_name,
+ show_flags);
else
bgp_show(vty, abgp, afi, safi,
sh_type, output_arg,
diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h
index 1b04bfc71..3fa58c0df 100644
--- a/bgpd/bgp_route.h
+++ b/bgpd/bgp_route.h
@@ -80,7 +80,7 @@ enum bgp_show_adj_route_type {
#define BGP_SHOW_NCODE_HEADER "Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self\n"
#define BGP_SHOW_RPKI_HEADER \
"RPKI validation codes: V valid, I invalid, N Not found\n\n"
-#define BGP_SHOW_HEADER " Network Next Hop Metric LocPrf Weight Path\n"
+#define BGP_SHOW_HEADER " Network Next Hop Metric LocPrf Weight Path\n"
#define BGP_SHOW_HEADER_WIDE " Network Next Hop Metric LocPrf Weight Path\n"
/* Maximum number of labels we can process or send with a prefix. We
@@ -294,7 +294,7 @@ struct bgp_path_info {
int lock;
/* BGP information status. */
- uint16_t flags;
+ uint32_t flags;
#define BGP_PATH_IGP_CHANGED (1 << 0)
#define BGP_PATH_DAMPED (1 << 1)
#define BGP_PATH_HISTORY (1 << 2)
@@ -311,6 +311,7 @@ struct bgp_path_info {
#define BGP_PATH_RIB_ATTR_CHG (1 << 13)
#define BGP_PATH_ANNC_NH_SELF (1 << 14)
#define BGP_PATH_LINK_BW_CHG (1 << 15)
+#define BGP_PATH_ACCEPT_OWN (1 << 16)
/* BGP route type. This can be static, RIP, OSPF, BGP etc. */
uint8_t type;
@@ -613,19 +614,35 @@ static inline bool bgp_check_advertise(struct bgp *bgp, struct bgp_dest *dest)
*/
static inline bool bgp_check_withdrawal(struct bgp *bgp, struct bgp_dest *dest)
{
- struct bgp_path_info *pi;
+ struct bgp_path_info *pi, *selected = NULL;
if (!BGP_SUPPRESS_FIB_ENABLED(bgp))
return false;
for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) {
- if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED))
+ if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) {
+ selected = pi;
continue;
+ }
if (pi->sub_type != BGP_ROUTE_NORMAL)
return true;
}
+ /*
+ * pi is selected and bgp is dealing with a static route
+ * ( ie a network statement of some sort ). FIB installed
+ * is irrelevant
+ *
+ * I am not sure what the above for loop is wanted in this
+ * manner at this point. But I do know that if I have
+ * a static route that is selected and it's the one
+ * being checked for should I withdrawal we do not
+ * want to withdraw the route on installation :)
+ */
+ if (selected && selected->sub_type == BGP_ROUTE_STATIC)
+ return false;
+
if (CHECK_FLAG(dest->flags, BGP_NODE_FIB_INSTALLED))
return false;
@@ -664,7 +681,12 @@ extern void bgp_default_originate(struct peer *, afi_t, safi_t, int);
extern void bgp_soft_reconfig_table_task_cancel(const struct bgp *bgp,
const struct bgp_table *table,
const struct peer *peer);
-extern void bgp_soft_reconfig_in(struct peer *, afi_t, safi_t);
+
+/*
+ * If this peer is configured for soft reconfig in then do the work
+ * and return true. If it is not return false; and do nothing
+ */
+extern bool bgp_soft_reconfig_in(struct peer *peer, afi_t afi, safi_t safi);
extern void bgp_clear_route(struct peer *, afi_t, safi_t);
extern void bgp_clear_route_all(struct peer *);
extern void bgp_clear_adj_in(struct peer *, afi_t, safi_t);
@@ -858,4 +880,6 @@ extern void subgroup_announce_reset_nhop(uint8_t family, struct attr *attr);
const char *
bgp_path_selection_reason2str(enum bgp_path_selection_reason reason);
extern bool bgp_addpath_encode_rx(struct peer *peer, afi_t afi, safi_t safi);
+extern const struct prefix_rd *bgp_rd_from_dest(const struct bgp_dest *dest,
+ safi_t safi);
#endif /* _QUAGGA_BGP_ROUTE_H */
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index ded47028a..b736e6c38 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -30,11 +30,16 @@
#include "log.h"
#include "frrlua.h"
#include "frrscript.h"
-#ifdef HAVE_LIBPCREPOSIX
+#ifdef HAVE_LIBPCRE2_POSIX
+#ifndef _FRR_PCRE2_POSIX
+#define _FRR_PCRE2_POSIX
+#include <pcre2posix.h>
+#endif /* _FRR_PCRE2_POSIX */
+#elif defined(HAVE_LIBPCREPOSIX)
#include <pcreposix.h>
#else
#include <regex.h>
-#endif /* HAVE_LIBPCREPOSIX */
+#endif /* HAVE_LIBPCRE2_POSIX */
#include "buffer.h"
#include "sockunion.h"
#include "hash.h"
@@ -74,9 +79,7 @@
#include "bgpd/rfapi/bgp_rfapi_cfg.h"
#endif
-#ifndef VTYSH_EXTRACT_PL
#include "bgpd/bgp_routemap_clippy.c"
-#endif
/* Memo of route-map commands.
@@ -643,6 +646,20 @@ route_match_prefix_list_flowspec(afi_t afi, struct prefix_list *plist,
}
static enum route_map_cmd_result_t
+route_match_prefix_list_evpn(afi_t afi, struct prefix_list *plist,
+ const struct prefix *p)
+{
+ /* Convert to match a general plist */
+ struct prefix new;
+
+ if (evpn_prefix2prefix(p, &new))
+ return RMAP_NOMATCH;
+
+ return (prefix_list_apply(plist, &new) == PREFIX_DENY ? RMAP_NOMATCH
+ : RMAP_MATCH);
+}
+
+static enum route_map_cmd_result_t
route_match_address_prefix_list(void *rule, afi_t afi,
const struct prefix *prefix, void *object)
{
@@ -655,6 +672,10 @@ route_match_address_prefix_list(void *rule, afi_t afi,
if (prefix->family == AF_FLOWSPEC)
return route_match_prefix_list_flowspec(afi, plist,
prefix);
+
+ else if (prefix->family == AF_EVPN)
+ return route_match_prefix_list_evpn(afi, plist, prefix);
+
return (prefix_list_apply(plist, prefix) == PREFIX_DENY ? RMAP_NOMATCH
: RMAP_MATCH);
}
@@ -3025,6 +3046,46 @@ static const struct route_map_rule_cmd route_set_atomic_aggregate_cmd = {
route_set_atomic_aggregate_free,
};
+/* AIGP TLV Metric */
+static enum route_map_cmd_result_t
+route_set_aigp_metric(void *rule, const struct prefix *pfx, void *object)
+{
+ const char *aigp_metric = rule;
+ struct bgp_path_info *path = object;
+ uint32_t aigp = 0;
+
+ if (strmatch(aigp_metric, "igp-metric")) {
+ if (!path->nexthop)
+ return RMAP_NOMATCH;
+
+ bgp_attr_set_aigp_metric(path->attr, path->nexthop->metric);
+ } else {
+ aigp = atoi(aigp_metric);
+ bgp_attr_set_aigp_metric(path->attr, aigp);
+ }
+
+ path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_AIGP);
+
+ return RMAP_OKAY;
+}
+
+static void *route_set_aigp_metric_compile(const char *arg)
+{
+ return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
+}
+
+static void route_set_aigp_metric_free(void *rule)
+{
+ XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+static const struct route_map_rule_cmd route_set_aigp_metric_cmd = {
+ "aigp-metric",
+ route_set_aigp_metric,
+ route_set_aigp_metric_compile,
+ route_set_aigp_metric_free,
+};
+
/* `set aggregator as AS A.B.C.D' */
struct aggregator {
as_t as;
@@ -6336,6 +6397,42 @@ DEFUN_YANG (no_set_atomic_aggregate,
return nb_cli_apply_changes(vty, NULL);
}
+DEFPY_YANG (set_aigp_metric,
+ set_aigp_metric_cmd,
+ "set aigp-metric <igp-metric|(1-4294967295)>$aigp_metric",
+ SET_STR
+ "BGP AIGP attribute (AIGP Metric TLV)\n"
+ "AIGP Metric value from IGP protocol\n"
+ "Manual AIGP Metric value\n")
+{
+ const char *xpath =
+ "./set-action[action='frr-bgp-route-map:aigp-metric']";
+ char xpath_value[XPATH_MAXLEN];
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/rmap-set-action/frr-bgp-route-map:aigp-metric", xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, aigp_metric);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY_YANG (no_set_aigp_metric,
+ no_set_aigp_metric_cmd,
+ "no set aigp-metric [<igp-metric|(1-4294967295)>]",
+ NO_STR
+ SET_STR
+ "BGP AIGP attribute (AIGP Metric TLV)\n"
+ "AIGP Metric value from IGP protocol\n"
+ "Manual AIGP Metric value\n")
+{
+ const char *xpath =
+ "./set-action[action='frr-bgp-route-map:aigp-metric']";
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+ return nb_cli_apply_changes(vty, NULL);
+}
+
DEFUN_YANG (set_aggregator_as,
set_aggregator_as_cmd,
"set aggregator as (1-4294967295) A.B.C.D",
@@ -6995,6 +7092,7 @@ void bgp_route_map_init(void)
route_map_install_set(&route_set_aspath_replace_cmd);
route_map_install_set(&route_set_origin_cmd);
route_map_install_set(&route_set_atomic_aggregate_cmd);
+ route_map_install_set(&route_set_aigp_metric_cmd);
route_map_install_set(&route_set_aggregator_as_cmd);
route_map_install_set(&route_set_community_cmd);
route_map_install_set(&route_set_community_delete_cmd);
@@ -7077,6 +7175,8 @@ void bgp_route_map_init(void)
install_element(RMAP_NODE, &no_set_origin_cmd);
install_element(RMAP_NODE, &set_atomic_aggregate_cmd);
install_element(RMAP_NODE, &no_set_atomic_aggregate_cmd);
+ install_element(RMAP_NODE, &set_aigp_metric_cmd);
+ install_element(RMAP_NODE, &no_set_aigp_metric_cmd);
install_element(RMAP_NODE, &set_aggregator_as_cmd);
install_element(RMAP_NODE, &no_set_aggregator_as_cmd);
install_element(RMAP_NODE, &set_community_cmd);
diff --git a/bgpd/bgp_routemap_nb.c b/bgpd/bgp_routemap_nb.c
index c47c37dc6..35e470349 100644
--- a/bgpd/bgp_routemap_nb.c
+++ b/bgpd/bgp_routemap_nb.c
@@ -283,6 +283,13 @@ const struct frr_yang_module_info frr_bgp_route_map_info = {
}
},
{
+ .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:aigp-metric",
+ .cbs = {
+ .modify = lib_route_map_entry_set_action_rmap_set_action_aigp_metric_modify,
+ .destroy = lib_route_map_entry_set_action_rmap_set_action_aigp_metric_destroy,
+ }
+ },
+ {
.xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:prepend-as-path",
.cbs = {
.modify = lib_route_map_entry_set_action_rmap_set_action_prepend_as_path_modify,
diff --git a/bgpd/bgp_routemap_nb.h b/bgpd/bgp_routemap_nb.h
index 163e3b55c..933204415 100644
--- a/bgpd/bgp_routemap_nb.h
+++ b/bgpd/bgp_routemap_nb.h
@@ -106,6 +106,10 @@ int lib_route_map_entry_set_action_rmap_set_action_table_modify(struct nb_cb_mod
int lib_route_map_entry_set_action_rmap_set_action_table_destroy(struct nb_cb_destroy_args *args);
int lib_route_map_entry_set_action_rmap_set_action_atomic_aggregate_create(struct nb_cb_create_args *args);
int lib_route_map_entry_set_action_rmap_set_action_atomic_aggregate_destroy(struct nb_cb_destroy_args *args);
+int lib_route_map_entry_set_action_rmap_set_action_aigp_metric_modify(
+ struct nb_cb_modify_args *args);
+int lib_route_map_entry_set_action_rmap_set_action_aigp_metric_destroy(
+ struct nb_cb_destroy_args *args);
int lib_route_map_entry_set_action_rmap_set_action_prepend_as_path_modify(struct nb_cb_modify_args *args);
int lib_route_map_entry_set_action_rmap_set_action_prepend_as_path_destroy(struct nb_cb_destroy_args *args);
int lib_route_map_entry_set_action_rmap_set_action_last_as_modify(struct nb_cb_modify_args *args);
diff --git a/bgpd/bgp_routemap_nb_config.c b/bgpd/bgp_routemap_nb_config.c
index b18cf9d4d..216bcc0b0 100644
--- a/bgpd/bgp_routemap_nb_config.c
+++ b/bgpd/bgp_routemap_nb_config.c
@@ -2090,6 +2090,58 @@ lib_route_map_entry_set_action_rmap_set_action_atomic_aggregate_destroy(
/*
* XPath:
+ * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:aigp-metric
+ */
+int lib_route_map_entry_set_action_rmap_set_action_aigp_metric_modify(
+ struct nb_cb_modify_args *args)
+{
+ struct routemap_hook_context *rhc;
+ const char *aigp;
+ int rv;
+
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ break;
+ case NB_EV_APPLY:
+ /* Add configuration. */
+ rhc = nb_running_get_entry(args->dnode, NULL, true);
+ aigp = yang_dnode_get_string(args->dnode, NULL);
+
+ /* Set destroy information. */
+ rhc->rhc_shook = generic_set_delete;
+ rhc->rhc_rule = "aigp-metric";
+ rhc->rhc_event = RMAP_EVENT_SET_DELETED;
+
+ rv = generic_set_add(rhc->rhc_rmi, rhc->rhc_rule, aigp,
+ args->errmsg, args->errmsg_len);
+ if (rv != CMD_SUCCESS) {
+ rhc->rhc_shook = NULL;
+ return NB_ERR_INCONSISTENCY;
+ }
+ }
+
+ return NB_OK;
+}
+
+int lib_route_map_entry_set_action_rmap_set_action_aigp_metric_destroy(
+ struct nb_cb_destroy_args *args)
+{
+ switch (args->event) {
+ case NB_EV_VALIDATE:
+ case NB_EV_PREPARE:
+ case NB_EV_ABORT:
+ break;
+ case NB_EV_APPLY:
+ return lib_route_map_entry_set_destroy(args);
+ }
+
+ return NB_OK;
+}
+
+/*
+ * XPath:
* /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:prepend-as-path
*/
int
diff --git a/bgpd/bgp_rpki.c b/bgpd/bgp_rpki.c
index b90c09c68..73c6fe0c4 100644
--- a/bgpd/bgp_rpki.c
+++ b/bgpd/bgp_rpki.c
@@ -52,20 +52,17 @@
#include "lib/network.h"
#include "lib/thread.h"
-#ifndef VTYSH_EXTRACT_PL
#include "rtrlib/rtrlib.h"
-#endif
#include "hook.h"
#include "libfrr.h"
#include "lib/version.h"
-#ifndef VTYSH_EXTRACT_PL
#include "bgpd/bgp_rpki_clippy.c"
-#endif
DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_CACHE, "BGP RPKI Cache server");
DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_CACHE_GROUP, "BGP RPKI Cache server group");
DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_RTRLIB, "BGP RPKI RTRLib");
+DEFINE_MTYPE_STATIC(BGPD, BGP_RPKI_REVALIDATE, "BGP RPKI Revalidation");
#define POLLING_PERIOD_DEFAULT 3600
#define EXPIRE_INTERVAL_DEFAULT 7200
@@ -375,10 +372,9 @@ inline bool is_stopping(void)
return rtr_is_stopping;
}
-static struct prefix *pfx_record_to_prefix(struct pfx_record *record)
+static void pfx_record_to_prefix(struct pfx_record *record,
+ struct prefix *prefix)
{
- struct prefix *prefix = prefix_new();
-
prefix->prefixlen = record->min_len;
if (record->prefix.ver == LRTR_IPV4) {
@@ -389,15 +385,41 @@ static struct prefix *pfx_record_to_prefix(struct pfx_record *record)
ipv6_addr_to_network_byte_order(record->prefix.u.addr6.addr,
prefix->u.prefix6.s6_addr32);
}
+}
+
+struct rpki_revalidate_prefix {
+ struct bgp *bgp;
+ struct prefix prefix;
+ afi_t afi;
+ safi_t safi;
+};
+
+static void rpki_revalidate_prefix(struct thread *thread)
+{
+ struct rpki_revalidate_prefix *rrp = THREAD_ARG(thread);
+ struct bgp_dest *match, *node;
- return prefix;
+ match = bgp_table_subtree_lookup(rrp->bgp->rib[rrp->afi][rrp->safi],
+ &rrp->prefix);
+
+ node = match;
+
+ while (node) {
+ if (bgp_dest_has_bgp_path_info_data(node)) {
+ revalidate_bgp_node(node, rrp->afi, rrp->safi);
+ }
+
+ node = bgp_route_next_until(node, match);
+ }
+
+ XFREE(MTYPE_BGP_RPKI_REVALIDATE, rrp);
}
static void bgpd_sync_callback(struct thread *thread)
{
struct bgp *bgp;
struct listnode *node;
- struct prefix *prefix;
+ struct prefix prefix;
struct pfx_record rec;
thread_add_read(bm->master, bgpd_sync_callback, NULL,
@@ -420,7 +442,7 @@ static void bgpd_sync_callback(struct thread *thread)
RPKI_DEBUG("Could not read from rpki_sync_socket_bgpd");
return;
}
- prefix = pfx_record_to_prefix(&rec);
+ pfx_record_to_prefix(&rec, &prefix);
afi_t afi = (rec.prefix.ver == LRTR_IPV4) ? AFI_IP : AFI_IP6;
@@ -429,30 +451,20 @@ static void bgpd_sync_callback(struct thread *thread)
for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) {
struct bgp_table *table = bgp->rib[afi][safi];
+ struct rpki_revalidate_prefix *rrp;
if (!table)
continue;
- struct bgp_dest *match;
- struct bgp_dest *node;
-
- match = bgp_table_subtree_lookup(table, prefix);
- node = match;
-
- while (node) {
- if (bgp_dest_has_bgp_path_info_data(node)) {
- revalidate_bgp_node(node, afi, safi);
- }
-
- node = bgp_route_next_until(node, match);
- }
-
- if (match)
- bgp_dest_unlock_node(match);
+ rrp = XCALLOC(MTYPE_BGP_RPKI_REVALIDATE, sizeof(*rrp));
+ rrp->bgp = bgp;
+ rrp->prefix = prefix;
+ rrp->afi = afi;
+ rrp->safi = safi;
+ thread_add_event(bm->master, rpki_revalidate_prefix,
+ rrp, 0, &bgp->t_revalidate[afi][safi]);
}
}
-
- prefix_free(&prefix);
}
static void revalidate_bgp_node(struct bgp_dest *bgp_dest, afi_t afi,
@@ -477,6 +489,31 @@ static void revalidate_bgp_node(struct bgp_dest *bgp_dest, afi_t afi,
}
}
+/*
+ * The act of a soft reconfig in revalidation is really expensive
+ * coupled with the fact that the download of a full rpki state
+ * from a rpki server can be expensive, let's break up the revalidation
+ * to a point in time in the future to allow other bgp events
+ * to take place too.
+ */
+struct rpki_revalidate_peer {
+ afi_t afi;
+ safi_t safi;
+ struct peer *peer;
+};
+
+static void bgp_rpki_revalidate_peer(struct thread *thread)
+{
+ struct rpki_revalidate_peer *rvp = THREAD_ARG(thread);
+
+ /*
+ * Here's the expensive bit of gnomish deviousness
+ */
+ bgp_soft_reconfig_in(rvp->peer, rvp->afi, rvp->safi);
+
+ XFREE(MTYPE_BGP_RPKI_REVALIDATE, rvp);
+}
+
static void revalidate_all_routes(void)
{
struct bgp *bgp;
@@ -487,18 +524,28 @@ static void revalidate_all_routes(void)
struct listnode *peer_listnode;
for (ALL_LIST_ELEMENTS_RO(bgp->peer, peer_listnode, peer)) {
+ afi_t afi;
+ safi_t safi;
+
+ FOREACH_AFI_SAFI (afi, safi) {
+ struct rpki_revalidate_peer *rvp;
- for (size_t i = 0; i < 2; i++) {
- safi_t safi;
- afi_t afi = (i == 0) ? AFI_IP : AFI_IP6;
+ if (!bgp->rib[afi][safi])
+ continue;
- for (safi = SAFI_UNICAST; safi < SAFI_MAX;
- safi++) {
- if (!peer->bgp->rib[afi][safi])
- continue;
+ if (!peer_established(peer))
+ continue;
- bgp_soft_reconfig_in(peer, afi, safi);
- }
+ rvp = XCALLOC(MTYPE_BGP_RPKI_REVALIDATE,
+ sizeof(*rvp));
+ rvp->peer = peer;
+ rvp->afi = afi;
+ rvp->safi = safi;
+
+ thread_add_event(
+ bm->master, bgp_rpki_revalidate_peer,
+ rvp, 0,
+ &peer->t_revalidate_all[afi][safi]);
}
}
}
@@ -592,7 +639,7 @@ static int bgp_rpki_module_init(void)
hook_register(bgp_rpki_prefix_status, rpki_validate_prefix);
hook_register(frr_late_init, bgp_rpki_init);
- hook_register(frr_early_fini, &bgp_rpki_fini);
+ hook_register(frr_early_fini, bgp_rpki_fini);
return 0;
}
@@ -1688,7 +1735,7 @@ DEFUN_YANG (no_match_rpki,
const char *xpath =
"./match-condition[condition='frr-bgp-route-map:rpki']";
- nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
return nb_cli_apply_changes(vty, NULL);
}
diff --git a/bgpd/bgp_table.h b/bgpd/bgp_table.h
index 86cd4f3da..121afc481 100644
--- a/bgpd/bgp_table.h
+++ b/bgpd/bgp_table.h
@@ -63,7 +63,9 @@ enum bgp_path_selection_reason {
bgp_path_selection_evpn_lower_ip,
bgp_path_selection_weight,
bgp_path_selection_local_pref,
+ bgp_path_selection_accept_own,
bgp_path_selection_local_route,
+ bgp_path_selection_aigp,
bgp_path_selection_confed_as_path,
bgp_path_selection_as_path,
bgp_path_selection_origin,
diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c
index 0219535b0..9d550fd19 100644
--- a/bgpd/bgp_updgrp.c
+++ b/bgpd/bgp_updgrp.c
@@ -436,6 +436,11 @@ static unsigned int updgrp_hash_key_make(const void *p)
*/
key = jhash_1word(peer->local_role, key);
+ /* Neighbors configured with the AIGP attribute are put in a separate
+ * update group from other neighbors.
+ */
+ key = jhash_1word((peer->flags & PEER_FLAG_AIGP), key);
+
if (peer->soo[afi][safi]) {
char *soo_str = ecommunity_str(peer->soo[afi][safi]);
diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c
index 27e367770..72e70ebf9 100644
--- a/bgpd/bgp_updgrp_adv.c
+++ b/bgpd/bgp_updgrp_adv.c
@@ -355,6 +355,11 @@ static int update_group_announce_walkcb(struct update_group *updgrp, void *arg)
struct update_subgroup *subgrp;
UPDGRP_FOREACH_SUBGRP (updgrp, subgrp) {
+ /* Avoid supressing duplicate routes later
+ * when processing in subgroup_announce_table().
+ */
+ SET_FLAG(subgrp->sflags, SUBGRP_STATUS_FORCE_UPDATES);
+
subgroup_announce_all(subgrp);
}
diff --git a/bgpd/bgp_updgrp_packet.c b/bgpd/bgp_updgrp_packet.c
index 88a81f255..9de97cf06 100644
--- a/bgpd/bgp_updgrp_packet.c
+++ b/bgpd/bgp_updgrp_packet.c
@@ -527,7 +527,7 @@ struct stream *bpacket_reformat_for_peer(struct bpacket *pkt,
&& !CHECK_FLAG(vec->flags,
BPKT_ATTRVEC_FLAGS_RMAP_NH_UNCHANGED)
&& !peer_af_flag_check(
- peer, nhafi, paf->safi,
+ peer, paf->afi, paf->safi,
PEER_FLAG_NEXTHOP_UNCHANGED)) {
/* NOTE: not handling case where NH has new AFI
*/
@@ -752,7 +752,7 @@ struct bpacket *subgroup_update_packet(struct update_subgroup *subgrp)
* attr. */
total_attr_len = bgp_packet_attribute(
NULL, peer, s, adv->baa->attr, &vecarr, NULL,
- afi, safi, from, NULL, NULL, 0, 0, 0);
+ afi, safi, from, NULL, NULL, 0, 0, 0, path);
space_remaining =
STREAM_CONCAT_REMAIN(s, snlri, STREAM_SIZE(s))
@@ -1125,7 +1125,8 @@ void subgroup_default_update_packet(struct update_subgroup *subgrp,
stream_putw(s, 0);
total_attr_len = bgp_packet_attribute(
NULL, peer, s, attr, &vecarr, &p, afi, safi, from, NULL, NULL,
- 0, addpath_capable, BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE);
+ 0, addpath_capable, BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE,
+ NULL);
/* Set Total Path Attribute Length. */
stream_putw_at(s, pos, total_attr_len);
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 5b4a56233..6f0bd5ede 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -78,6 +78,8 @@
#ifdef ENABLE_BGP_VNC
#include "bgpd/rfapi/bgp_rfapi_cfg.h"
#endif
+#include "bgpd/bgp_orr.h"
+
FRR_CFG_DEFAULT_BOOL(BGP_IMPORT_CHECK,
{
@@ -298,7 +300,6 @@ static int bgp_srv6_locator_unset(struct bgp *bgp)
struct srv6_locator_chunk *chunk;
struct bgp_srv6_function *func;
struct bgp *bgp_vrf;
- struct in6_addr *tovpn_sid;
/* release chunk notification via ZAPI */
ret = bgp_zebra_srv6_manager_release_locator_chunk(
@@ -309,7 +310,7 @@ static int bgp_srv6_locator_unset(struct bgp *bgp)
/* refresh chunks */
for (ALL_LIST_ELEMENTS(bgp->srv6_locator_chunks, node, nnode, chunk)) {
listnode_delete(bgp->srv6_locator_chunks, chunk);
- srv6_locator_chunk_free(chunk);
+ srv6_locator_chunk_free(&chunk);
}
/* refresh functions */
@@ -324,16 +325,15 @@ static int bgp_srv6_locator_unset(struct bgp *bgp)
continue;
/* refresh vpnv4 tovpn_sid */
- tovpn_sid = bgp_vrf->vpn_policy[AFI_IP].tovpn_sid;
- if (tovpn_sid)
- XFREE(MTYPE_BGP_SRV6_SID,
- bgp_vrf->vpn_policy[AFI_IP].tovpn_sid);
+ XFREE(MTYPE_BGP_SRV6_SID,
+ bgp_vrf->vpn_policy[AFI_IP].tovpn_sid);
/* refresh vpnv6 tovpn_sid */
- tovpn_sid = bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid;
- if (tovpn_sid)
- XFREE(MTYPE_BGP_SRV6_SID,
- bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid);
+ XFREE(MTYPE_BGP_SRV6_SID,
+ bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid);
+
+ /* refresh per-vrf tovpn_sid */
+ XFREE(MTYPE_BGP_SRV6_SID, bgp_vrf->tovpn_sid);
}
/* update vpn bgp processes */
@@ -345,12 +345,15 @@ static int bgp_srv6_locator_unset(struct bgp *bgp)
continue;
/* refresh vpnv4 tovpn_sid_locator */
- XFREE(MTYPE_BGP_SRV6_SID,
- bgp_vrf->vpn_policy[AFI_IP].tovpn_sid_locator);
+ srv6_locator_chunk_free(
+ &bgp_vrf->vpn_policy[AFI_IP].tovpn_sid_locator);
/* refresh vpnv6 tovpn_sid_locator */
- XFREE(MTYPE_BGP_SRV6_SID,
- bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid_locator);
+ srv6_locator_chunk_free(
+ &bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid_locator);
+
+ /* refresh per-vrf tovpn_sid_locator */
+ srv6_locator_chunk_free(&bgp_vrf->tovpn_sid_locator);
}
/* clear locator name */
@@ -942,6 +945,9 @@ int bgp_vty_return(struct vty *vty, enum bgp_create_error_code ret)
case BGP_ERR_INVALID_INTERNAL_ROLE:
str = "External roles can be set only on eBGP session";
break;
+ case BGP_ERR_PEER_ORR_CONFIGURED:
+ str = "Deconfigure optimal-route-reflection on this peer first";
+ break;
}
if (str) {
vty_out(vty, "%% %s\n", str);
@@ -1302,9 +1308,7 @@ void bgp_clear_soft_in(struct bgp *bgp, afi_t afi, safi_t safi)
bgp_clear(NULL, bgp, afi, safi, clear_all, BGP_CLEAR_SOFT_IN, NULL);
}
-#ifndef VTYSH_EXTRACT_PL
#include "bgpd/bgp_vty_clippy.c"
-#endif
DEFUN_HIDDEN (bgp_local_mac,
bgp_local_mac_cmd,
@@ -2348,6 +2352,15 @@ void bgp_config_write_coalesce_time(struct vty *vty, struct bgp *bgp)
vty_out(vty, " coalesce-time %u\n", bgp->coalesce_time);
}
+/* BGP TCP keepalive */
+static void bgp_config_tcp_keepalive(struct vty *vty, struct bgp *bgp)
+{
+ if (bgp->tcp_keepalive_idle) {
+ vty_out(vty, " bgp tcp-keepalive %u %u %u\n",
+ bgp->tcp_keepalive_idle, bgp->tcp_keepalive_intvl,
+ bgp->tcp_keepalive_probes);
+ }
+}
DEFUN (bgp_coalesce_time,
bgp_coalesce_time_cmd,
@@ -2571,6 +2584,38 @@ DEFUN(no_bgp_minimum_holdtime, no_bgp_minimum_holdtime_cmd,
return CMD_SUCCESS;
}
+DEFPY(bgp_tcp_keepalive, bgp_tcp_keepalive_cmd,
+ "bgp tcp-keepalive (1-65535)$idle (1-65535)$intvl (1-30)$probes",
+ BGP_STR
+ "TCP keepalive parameters\n"
+ "TCP keepalive idle time (seconds)\n"
+ "TCP keepalive interval (seconds)\n"
+ "TCP keepalive maximum probes\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+ bgp_tcp_keepalive_set(bgp, (uint16_t)idle, (uint16_t)intvl,
+ (uint16_t)probes);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(no_bgp_tcp_keepalive, no_bgp_tcp_keepalive_cmd,
+ "no bgp tcp-keepalive [(1-65535) (1-65535) (1-30)]",
+ NO_STR
+ BGP_STR
+ "TCP keepalive parameters\n"
+ "TCP keepalive idle time (seconds)\n"
+ "TCP keepalive interval (seconds)\n"
+ "TCP keepalive maximum probes\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+ bgp_tcp_keepalive_unset(bgp);
+
+ return CMD_SUCCESS;
+}
+
DEFUN (bgp_client_to_client_reflection,
bgp_client_to_client_reflection_cmd,
"bgp client-to-client reflection",
@@ -3349,7 +3394,7 @@ DEFUN (no_bgp_graceful_restart_rib_stale_time,
}
DEFUN(bgp_llgr_stalepath_time, bgp_llgr_stalepath_time_cmd,
- "bgp long-lived-graceful-restart stale-time (1-4294967295)",
+ "bgp long-lived-graceful-restart stale-time (1-16777215)",
BGP_STR
"Enable Long-lived Graceful Restart\n"
"Specifies maximum time to wait before purging long-lived stale routes\n"
@@ -3366,7 +3411,7 @@ DEFUN(bgp_llgr_stalepath_time, bgp_llgr_stalepath_time_cmd,
}
DEFUN(no_bgp_llgr_stalepath_time, no_bgp_llgr_stalepath_time_cmd,
- "no bgp long-lived-graceful-restart stale-time [(1-4294967295)]",
+ "no bgp long-lived-graceful-restart stale-time [(1-16777215)]",
NO_STR BGP_STR
"Enable Long-lived Graceful Restart\n"
"Specifies maximum time to wait before purging long-lived stale routes\n"
@@ -3520,6 +3565,26 @@ DEFUN (no_bgp_fast_external_failover,
return CMD_SUCCESS;
}
+DEFPY (bgp_bestpath_aigp,
+ bgp_bestpath_aigp_cmd,
+ "[no$no] bgp bestpath aigp",
+ NO_STR
+ BGP_STR
+ "Change the default bestpath selection\n"
+ "Evaluate the AIGP attribute during the best path selection process\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+ if (no)
+ UNSET_FLAG(bgp->flags, BGP_FLAG_COMPARE_AIGP);
+ else
+ SET_FLAG(bgp->flags, BGP_FLAG_COMPARE_AIGP);
+
+ bgp_recalculate_all_bestpaths(bgp);
+
+ return CMD_SUCCESS;
+}
+
/* "bgp bestpath compare-routerid" configuration. */
DEFUN (bgp_bestpath_compare_router_id,
bgp_bestpath_compare_router_id_cmd,
@@ -5207,8 +5272,10 @@ static int peer_flag_modify_vty(struct vty *vty, const char *ip_str,
return CMD_WARNING_CONFIG_FAILED;
}
- if (!set && flag == PEER_FLAG_SHUTDOWN)
+ if (!set && flag == PEER_FLAG_SHUTDOWN) {
peer_tx_shutdown_message_unset(peer);
+ UNSET_FLAG(peer->sflags, PEER_STATUS_RTT_SHUTDOWN);
+ }
if (set)
ret = peer_flag_set(peer, flag);
@@ -5767,7 +5834,7 @@ ALIAS_HIDDEN(neighbor_remove_private_as_all,
"neighbor <A.B.C.D|X:X::X:X|WORD> remove-private-AS all",
NEIGHBOR_STR NEIGHBOR_ADDR_STR2
"Remove private ASNs in outbound updates\n"
- "Apply to all AS numbers")
+ "Apply to all AS numbers\n")
DEFUN (neighbor_remove_private_as_replace_as,
neighbor_remove_private_as_replace_as_cmd,
@@ -6157,6 +6224,43 @@ ALIAS_HIDDEN(no_neighbor_route_reflector_client,
NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
"Configure a neighbor as Route Reflector client\n")
+/* optimal-route-reflection Root Routers configuration */
+DEFPY (optimal_route_reflection,
+ optimal_route_reflection_cmd,
+ "[no$no] optimal-route-reflection WORD$orr_group [<A.B.C.D|X:X::X:X>$primary [<A.B.C.D|X:X::X:X>$secondary [<A.B.C.D|X:X::X:X>$tertiary]]]",
+ NO_STR
+ "Create ORR group and assign root router(s)\n"
+ "ORR Group name\n"
+ "Primary Root address\n"
+ "Primary Root IPv6 address\n"
+ "Secondary Root address\n"
+ "Secondary Root IPv6 address\n"
+ "Tertiary Root address\n"
+ "Tertiary Root IPv6 address\n")
+{
+ if (!no && !primary) {
+ vty_out(vty, "%% Specify Primary Root address\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ return bgp_afi_safi_orr_group_set_vty(
+ vty, bgp_node_afi(vty), bgp_node_safi(vty), orr_group,
+ primary_str, secondary_str, tertiary_str, !!no);
+}
+
+/* neighbor optimal-route-reflection group*/
+DEFPY (neighbor_optimal_route_reflection,
+ neighbor_optimal_route_reflection_cmd,
+ "[no$no] neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor optimal-route-reflection WORD$orr_group",
+ NO_STR
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ "Apply ORR group configuration to the neighbor\n"
+ "ORR group name\n")
+{
+ return peer_orr_group_set_vty(vty, neighbor, bgp_node_afi(vty),
+ bgp_node_safi(vty), orr_group, !!no);
+}
+
/* neighbor route-server-client. */
DEFUN (neighbor_route_server_client,
neighbor_route_server_client_cmd,
@@ -6463,6 +6567,26 @@ DEFUN (no_neighbor_ebgp_multihop,
return peer_ebgp_multihop_unset_vty(vty, argv[idx_peer]->arg);
}
+DEFPY (neighbor_aigp,
+ neighbor_aigp_cmd,
+ "[no$no] neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor aigp",
+ NO_STR
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ "Enable send and receive of the AIGP attribute per neighbor\n")
+{
+ struct peer *peer;
+
+ peer = peer_and_group_lookup_vty(vty, neighbor);
+ if (!peer)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ if (no)
+ return peer_flag_unset_vty(vty, neighbor, PEER_FLAG_AIGP);
+ else
+ return peer_flag_set_vty(vty, neighbor, PEER_FLAG_AIGP);
+}
+
static uint8_t get_role_by_name(const char *role_str)
{
if (strncmp(role_str, "peer", 2) == 0)
@@ -8241,6 +8365,32 @@ ALIAS_HIDDEN(
"Only give warning message when limit is exceeded\n"
"Force checking all received routes not only accepted\n")
+/* "neighbor accept-own" */
+DEFPY (neighbor_accept_own,
+ neighbor_accept_own_cmd,
+ "[no$no] neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor accept-own",
+ NO_STR
+ NEIGHBOR_STR
+ NEIGHBOR_ADDR_STR2
+ "Enable handling of self-originated VPN routes containing ACCEPT_OWN community\n")
+{
+ struct peer *peer;
+ afi_t afi = bgp_node_afi(vty);
+ safi_t safi = bgp_node_safi(vty);
+ int ret;
+
+ peer = peer_and_group_lookup_vty(vty, neighbor);
+ if (!peer)
+ return CMD_WARNING_CONFIG_FAILED;
+
+ if (no)
+ ret = peer_af_flag_unset(peer, afi, safi, PEER_FLAG_ACCEPT_OWN);
+ else
+ ret = peer_af_flag_set(peer, afi, safi, PEER_FLAG_ACCEPT_OWN);
+
+ return bgp_vty_return(vty, ret);
+}
+
/* "neighbor soo" */
DEFPY (neighbor_soo,
neighbor_soo_cmd,
@@ -8854,7 +9004,7 @@ DEFPY (af_label_vpn_export,
DEFPY (af_sid_vpn_export,
af_sid_vpn_export_cmd,
- "[no] sid vpn export <(1-255)$sid_idx|auto$sid_auto>",
+ "[no] sid vpn export <(1-1048575)$sid_idx|auto$sid_auto>",
NO_STR
"sid value for VRF\n"
"Between current address-family and vpn\n"
@@ -8883,6 +9033,14 @@ DEFPY (af_sid_vpn_export,
return CMD_WARNING_CONFIG_FAILED;
}
+ if (bgp->tovpn_sid_index != 0 ||
+ CHECK_FLAG(bgp->vrf_flags, BGP_VRF_TOVPN_SID_AUTO)) {
+ vty_out(vty,
+ "per-vrf sid and per-af sid are mutually exclusive\n"
+ "Failed: per-vrf sid is configured. Remove per-vrf sid before configuring per-af sid\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
/* skip when it's already configured */
if ((sid_idx != 0 && bgp->vpn_policy[afi].tovpn_sid_index != 0)
|| (sid_auto && CHECK_FLAG(bgp->vpn_policy[afi].flags,
@@ -8924,6 +9082,92 @@ DEFPY (af_sid_vpn_export,
return CMD_SUCCESS;
}
+DEFPY (bgp_sid_vpn_export,
+ bgp_sid_vpn_export_cmd,
+ "[no] sid vpn per-vrf export <(1-255)$sid_idx|auto$sid_auto>",
+ NO_STR
+ "sid value for VRF\n"
+ "Between current vrf and vpn\n"
+ "sid per-VRF (both IPv4 and IPv6 address families)\n"
+ "For routes leaked from current vrf to vpn\n"
+ "Sid allocation index\n"
+ "Automatically assign a label\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+ int debug;
+
+ debug = (BGP_DEBUG(vpn, VPN_LEAK_TO_VRF) |
+ BGP_DEBUG(vpn, VPN_LEAK_FROM_VRF));
+
+ if (no) {
+ /* when per-VRF SID is not set, do nothing */
+ if (bgp->tovpn_sid_index == 0 &&
+ !CHECK_FLAG(bgp->vrf_flags, BGP_VRF_TOVPN_SID_AUTO))
+ return CMD_SUCCESS;
+
+ sid_idx = 0;
+ sid_auto = false;
+ bgp->tovpn_sid_index = 0;
+ UNSET_FLAG(bgp->vrf_flags, BGP_VRF_TOVPN_SID_AUTO);
+ }
+
+ if (bgp->vpn_policy[AFI_IP].tovpn_sid_index != 0 ||
+ CHECK_FLAG(bgp->vpn_policy[AFI_IP].flags,
+ BGP_VPN_POLICY_TOVPN_SID_AUTO) ||
+ bgp->vpn_policy[AFI_IP6].tovpn_sid_index != 0 ||
+ CHECK_FLAG(bgp->vpn_policy[AFI_IP6].flags,
+ BGP_VPN_POLICY_TOVPN_SID_AUTO)) {
+ vty_out(vty,
+ "per-vrf sid and per-af sid are mutually exclusive\n"
+ "Failed: per-af sid is configured. Remove per-af sid before configuring per-vrf sid\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ /* skip when it's already configured */
+ if ((sid_idx != 0 && bgp->tovpn_sid_index != 0) ||
+ (sid_auto && CHECK_FLAG(bgp->vrf_flags, BGP_VRF_TOVPN_SID_AUTO)))
+ return CMD_SUCCESS;
+
+ /*
+ * mode change between sid_idx and sid_auto isn't supported.
+ * user must negate sid vpn export when they want to change the mode
+ */
+ if ((sid_auto && bgp->tovpn_sid_index != 0) ||
+ (sid_idx != 0 &&
+ CHECK_FLAG(bgp->vrf_flags, BGP_VRF_TOVPN_SID_AUTO))) {
+ vty_out(vty, "it's already configured as %s.\n",
+ sid_auto ? "auto-mode" : "idx-mode");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ /* pre-change */
+ vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, AFI_IP, bgp_get_default(),
+ bgp);
+ vpn_leak_prechange(BGP_VPN_POLICY_DIR_TOVPN, AFI_IP6, bgp_get_default(),
+ bgp);
+
+ if (sid_auto) {
+ /* SID allocation auto-mode */
+ if (debug)
+ zlog_debug("%s: auto per-vrf sid alloc.", __func__);
+ SET_FLAG(bgp->vrf_flags, BGP_VRF_TOVPN_SID_AUTO);
+ } else if (sid_idx != 0) {
+ /* SID allocation index-mode */
+ if (debug)
+ zlog_debug("%s: idx %ld per-vrf sid alloc.", __func__,
+ sid_idx);
+ bgp->tovpn_sid_index = sid_idx;
+ }
+
+ /* post-change */
+ vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, AFI_IP, bgp_get_default(),
+ bgp);
+ vpn_leak_postchange(BGP_VPN_POLICY_DIR_TOVPN, AFI_IP6,
+ bgp_get_default(), bgp);
+
+ return CMD_SUCCESS;
+}
+
ALIAS (af_label_vpn_export,
af_no_label_vpn_export_cmd,
"no label vpn export",
@@ -8932,6 +9176,15 @@ ALIAS (af_label_vpn_export,
"Between current address-family and vpn\n"
"For routes leaked from current address-family to vpn\n")
+ALIAS (bgp_sid_vpn_export,
+ no_bgp_sid_vpn_export_cmd,
+ "no$no sid vpn per-vrf export",
+ NO_STR
+ "sid value for VRF\n"
+ "Between current vrf and vpn\n"
+ "sid per-VRF (both IPv4 and IPv6 address families)\n"
+ "For routes leaked from current vrf to vpn\n")
+
DEFPY (af_nexthop_vpn_export,
af_nexthop_vpn_export_cmd,
"[no] nexthop vpn export [<A.B.C.D|X:X::X:X>$nexthop_su]",
@@ -9631,11 +9884,7 @@ DEFPY (show_bgp_srv6,
struct listnode *node;
struct srv6_locator_chunk *chunk;
struct bgp_srv6_function *func;
- struct in6_addr *tovpn4_sid;
- struct in6_addr *tovpn6_sid;
char buf[256];
- char buf_tovpn4_sid[256];
- char buf_tovpn6_sid[256];
bgp = bgp_get_default();
if (!bgp)
@@ -9643,8 +9892,14 @@ DEFPY (show_bgp_srv6,
vty_out(vty, "locator_name: %s\n", bgp->srv6_locator_name);
vty_out(vty, "locator_chunks:\n");
- for (ALL_LIST_ELEMENTS_RO(bgp->srv6_locator_chunks, node, chunk))
+ for (ALL_LIST_ELEMENTS_RO(bgp->srv6_locator_chunks, node, chunk)) {
vty_out(vty, "- %pFX\n", &chunk->prefix);
+ vty_out(vty, " block-length: %d\n", chunk->block_bits_length);
+ vty_out(vty, " node-length: %d\n", chunk->node_bits_length);
+ vty_out(vty, " func-length: %d\n",
+ chunk->function_bits_length);
+ vty_out(vty, " arg-length: %d\n", chunk->argument_bits_length);
+ }
vty_out(vty, "functions:\n");
for (ALL_LIST_ELEMENTS_RO(bgp->srv6_functions, node, func)) {
@@ -9658,19 +9913,11 @@ DEFPY (show_bgp_srv6,
vty_out(vty, "- name: %s\n",
bgp->name ? bgp->name : "default");
- tovpn4_sid = bgp->vpn_policy[AFI_IP].tovpn_sid;
- tovpn6_sid = bgp->vpn_policy[AFI_IP6].tovpn_sid;
- if (tovpn4_sid)
- inet_ntop(AF_INET6, tovpn4_sid, buf_tovpn4_sid,
- sizeof(buf_tovpn4_sid));
- if (tovpn6_sid)
- inet_ntop(AF_INET6, tovpn6_sid, buf_tovpn6_sid,
- sizeof(buf_tovpn6_sid));
-
- vty_out(vty, " vpn_policy[AFI_IP].tovpn_sid: %s\n",
- tovpn4_sid ? buf_tovpn4_sid : "none");
- vty_out(vty, " vpn_policy[AFI_IP6].tovpn_sid: %s\n",
- tovpn6_sid ? buf_tovpn6_sid : "none");
+ vty_out(vty, " vpn_policy[AFI_IP].tovpn_sid: %pI6\n",
+ bgp->vpn_policy[AFI_IP].tovpn_sid);
+ vty_out(vty, " vpn_policy[AFI_IP6].tovpn_sid: %pI6\n",
+ bgp->vpn_policy[AFI_IP6].tovpn_sid);
+ vty_out(vty, " per-vrf tovpn_sid: %pI6\n", bgp->tovpn_sid);
}
return CMD_SUCCESS;
@@ -12067,6 +12314,16 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi,
json_addr,
"privateAsNumsRemovedInUpdatesToNbr");
+ if (CHECK_FLAG(p->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN)) {
+ if (CHECK_FLAG(p->af_flags[afi][safi],
+ PEER_FLAG_ALLOWAS_IN_ORIGIN))
+ json_object_boolean_true_add(json_addr,
+ "allowAsInOrigin");
+ else
+ json_object_int_add(json_addr, "allowAsInCount",
+ p->allowas_in[afi][safi]);
+ }
+
if (p->addpath_type[afi][safi] != BGP_ADDPATH_NONE)
json_object_boolean_true_add(
json_addr,
@@ -12357,6 +12614,11 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi,
if (CHECK_FLAG(p->af_flags[afi][safi],
PEER_FLAG_RSERVER_CLIENT))
vty_out(vty, " Route-Server Client\n");
+
+ if (peer_af_flag_check(p, afi, safi, PEER_FLAG_ORR_GROUP))
+ vty_out(vty, " ORR group (configured) : %s\n",
+ p->orr_group_name[afi][safi]);
+
if (CHECK_FLAG(p->af_flags[afi][safi], PEER_FLAG_SOFT_RECONFIG))
vty_out(vty,
" Inbound soft reconfiguration allowed\n");
@@ -12378,6 +12640,17 @@ static void bgp_show_peer_afi(struct vty *vty, struct peer *p, afi_t afi,
vty_out(vty,
" Private AS numbers removed in updates to this neighbor\n");
+ if (CHECK_FLAG(p->af_flags[afi][safi], PEER_FLAG_ALLOWAS_IN)) {
+ if (CHECK_FLAG(p->af_flags[afi][safi],
+ PEER_FLAG_ALLOWAS_IN_ORIGIN))
+ vty_out(vty,
+ " Local AS allowed as path origin\n");
+ else
+ vty_out(vty,
+ " Local AS allowed in path, %d occurrences\n",
+ p->allowas_in[afi][safi]);
+ }
+
if (p->addpath_type[afi][safi] != BGP_ADDPATH_NONE)
vty_out(vty, " %s\n",
bgp_addpath_names(p->addpath_type[afi][safi])
@@ -14294,9 +14567,18 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
if (use_json) {
json_object_int_add(json_neigh, "connectRetryTimer",
p->v_connect);
- if (peer_established(p) && p->rtt)
+ if (peer_established(p)) {
json_object_int_add(json_neigh, "estimatedRttInMsecs",
p->rtt);
+ if (CHECK_FLAG(p->flags, PEER_FLAG_RTT_SHUTDOWN)) {
+ json_object_int_add(json_neigh,
+ "shutdownRttInMsecs",
+ p->rtt_expected);
+ json_object_int_add(json_neigh,
+ "shutdownRttAfterCount",
+ p->rtt_keepalive_rcv);
+ }
+ }
if (p->t_start)
json_object_int_add(
json_neigh, "nextStartTimerDueInMsecs",
@@ -14331,9 +14613,14 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
} else {
vty_out(vty, "BGP Connect Retry Timer in Seconds: %d\n",
p->v_connect);
- if (peer_established(p) && p->rtt)
+ if (peer_established(p)) {
vty_out(vty, "Estimated round trip time: %d ms\n",
p->rtt);
+ if (CHECK_FLAG(p->flags, PEER_FLAG_RTT_SHUTDOWN))
+ vty_out(vty,
+ "Shutdown when RTT > %dms, count > %u\n",
+ p->rtt_expected, p->rtt_keepalive_rcv);
+ }
if (p->t_start)
vty_out(vty, "Next start timer due in %ld seconds\n",
thread_timer_remain_second(p->t_start));
@@ -16921,6 +17208,10 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
}
}
+ /* aigp */
+ if (peergroup_flag_check(peer, PEER_FLAG_AIGP))
+ vty_out(vty, " neighbor %s aigp\n", addr);
+
/* role */
if (peergroup_flag_check(peer, PEER_FLAG_ROLE) &&
peer->local_role != ROLE_UNDEFINED)
@@ -17284,6 +17575,10 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp,
}
}
+ /* accept-own */
+ if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_ACCEPT_OWN))
+ vty_out(vty, " neighbor %s accept-own\n", addr);
+
/* soo */
if (peergroup_af_flag_check(peer, afi, safi, PEER_FLAG_SOO)) {
char *soo_str = ecommunity_ecom2str(
@@ -17333,6 +17628,10 @@ static void bgp_config_write_peer_af(struct vty *vty, struct bgp *bgp,
: "");
}
}
+
+ if (peer_af_flag_check(peer, afi, safi, PEER_FLAG_ORR_GROUP))
+ vty_out(vty, " neighbor %s optimal-route-reflection %s\n",
+ addr, peer->orr_group_name[afi][safi]);
}
static void bgp_vpn_config_write(struct vty *vty, struct bgp *bgp, afi_t afi,
@@ -17439,6 +17738,9 @@ static void bgp_config_write_family(struct vty *vty, struct bgp *bgp, afi_t afi,
}
}
+ /* Optimal Route Reflection */
+ bgp_config_write_orr(vty, bgp, afi, safi);
+
vty_endframe(vty, " exit-address-family\n");
}
@@ -17451,6 +17753,7 @@ int bgp_config_write(struct vty *vty)
struct listnode *mnode, *mnnode;
afi_t afi;
safi_t safi;
+ uint32_t tovpn_sid_index = 0;
if (bm->rmap_update_timer != RMAP_DEFAULT_UPDATE_TIMER)
vty_out(vty, "bgp route-map delay-timer %u\n",
@@ -17480,6 +17783,10 @@ int bgp_config_write(struct vty *vty)
if (bm->tcp_dscp != IPTOS_PREC_INTERNETCONTROL)
vty_out(vty, "bgp session-dscp %u\n", bm->tcp_dscp >> 2);
+ /* BGP InQ limit */
+ if (bm->inq_limit != BM_DEFAULT_INQ_LIMIT)
+ vty_out(vty, "bgp input-queue-limit %u\n", bm->inq_limit);
+
/* BGP configuration. */
for (ALL_LIST_ELEMENTS(bm->bgp, mnode, mnnode, bgp)) {
@@ -17711,6 +18018,9 @@ int bgp_config_write(struct vty *vty)
vty_out(vty,
" bgp graceful-restart preserve-fw-state\n");
+ /* BGP TCP keepalive */
+ bgp_config_tcp_keepalive(vty, bgp);
+
/* Stale timer for RIB */
if (bgp->rib_stale_time != BGP_DEFAULT_RIB_STALE_TIME)
vty_out(vty,
@@ -17740,6 +18050,8 @@ int bgp_config_write(struct vty *vty)
}
if (CHECK_FLAG(bgp->flags, BGP_FLAG_COMPARE_ROUTER_ID))
vty_out(vty, " bgp bestpath compare-routerid\n");
+ if (CHECK_FLAG(bgp->flags, BGP_FLAG_COMPARE_AIGP))
+ vty_out(vty, " bgp bestpath aigp\n");
if (CHECK_FLAG(bgp->flags, BGP_FLAG_MED_CONFED)
|| CHECK_FLAG(bgp->flags, BGP_FLAG_MED_MISSING_AS_WORST)) {
vty_out(vty, " bgp bestpath med");
@@ -17832,6 +18144,13 @@ int bgp_config_write(struct vty *vty)
vty_endframe(vty, " exit\n");
}
+ tovpn_sid_index = bgp->tovpn_sid_index;
+ if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_TOVPN_SID_AUTO)) {
+ vty_out(vty, " sid vpn per-vrf export auto\n");
+ } else if (tovpn_sid_index != 0) {
+ vty_out(vty, " sid vpn per-vrf export %d\n",
+ tovpn_sid_index);
+ }
/* IPv4 unicast configuration. */
bgp_config_write_family(vty, bgp, AFI_IP, SAFI_UNICAST);
@@ -18182,6 +18501,31 @@ DEFPY(mpls_bgp_forwarding, mpls_bgp_forwarding_cmd,
return CMD_SUCCESS;
}
+DEFPY (bgp_inq_limit,
+ bgp_inq_limit_cmd,
+ "bgp input-queue-limit (1-4294967295)$limit",
+ BGP_STR
+ "Set the BGP Input Queue limit for all peers when message parsing\n"
+ "Input-Queue limit\n")
+{
+ bm->inq_limit = limit;
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (no_bgp_inq_limit,
+ no_bgp_inq_limit_cmd,
+ "no bgp input-queue-limit [(1-4294967295)$limit]",
+ NO_STR
+ BGP_STR
+ "Set the BGP Input Queue limit for all peers when message parsing\n"
+ "Input-Queue limit\n")
+{
+ bm->inq_limit = BM_DEFAULT_INQ_LIMIT;
+
+ return CMD_SUCCESS;
+}
+
/* Initialization of BGP interface. */
static void bgp_vty_if_init(void)
{
@@ -18231,6 +18575,10 @@ void bgp_vty_init(void)
install_default(BGP_EVPN_VNI_NODE);
install_default(BGP_SRV6_NODE);
+ /* "global bgp inq-limit command */
+ install_element(CONFIG_NODE, &bgp_inq_limit_cmd);
+ install_element(CONFIG_NODE, &no_bgp_inq_limit_cmd);
+
/* "bgp local-mac" hidden commands. */
install_element(CONFIG_NODE, &bgp_local_mac_cmd);
install_element(CONFIG_NODE, &no_bgp_local_mac_cmd);
@@ -18307,6 +18655,9 @@ void bgp_vty_init(void)
install_element(BGP_NODE, &neighbor_role_strict_cmd);
install_element(BGP_NODE, &no_neighbor_role_cmd);
+ /* "neighbor aigp" commands. */
+ install_element(BGP_NODE, &neighbor_aigp_cmd);
+
/* bgp disable-ebgp-connected-nh-check */
install_element(BGP_NODE, &bgp_disable_connected_route_check_cmd);
install_element(BGP_NODE, &no_bgp_disable_connected_route_check_cmd);
@@ -18426,6 +18777,10 @@ void bgp_vty_init(void)
install_element(BGP_NODE, &bgp_graceful_restart_rib_stale_time_cmd);
install_element(BGP_NODE, &no_bgp_graceful_restart_rib_stale_time_cmd);
+ /* "bgp inq-limit command */
+ install_element(BGP_NODE, &bgp_inq_limit_cmd);
+ install_element(BGP_NODE, &no_bgp_inq_limit_cmd);
+
/* "bgp graceful-shutdown" commands */
install_element(BGP_NODE, &bgp_graceful_shutdown_cmd);
install_element(BGP_NODE, &no_bgp_graceful_shutdown_cmd);
@@ -18441,6 +18796,9 @@ void bgp_vty_init(void)
install_element(BGP_NODE, &bgp_fast_external_failover_cmd);
install_element(BGP_NODE, &no_bgp_fast_external_failover_cmd);
+ /* "bgp bestpath aigp" commands */
+ install_element(BGP_NODE, &bgp_bestpath_aigp_cmd);
+
/* "bgp bestpath compare-routerid" commands */
install_element(BGP_NODE, &bgp_bestpath_compare_router_id_cmd);
install_element(BGP_NODE, &no_bgp_bestpath_compare_router_id_cmd);
@@ -18945,6 +19303,34 @@ void bgp_vty_init(void)
install_element(BGP_EVPN_NODE, &neighbor_route_reflector_client_cmd);
install_element(BGP_EVPN_NODE, &no_neighbor_route_reflector_client_cmd);
+ /* "optimal-route-reflection" commands */
+ install_element(BGP_IPV4_NODE, &optimal_route_reflection_cmd);
+ install_element(BGP_IPV4M_NODE, &optimal_route_reflection_cmd);
+ install_element(BGP_IPV4L_NODE, &optimal_route_reflection_cmd);
+ install_element(BGP_IPV6_NODE, &optimal_route_reflection_cmd);
+ install_element(BGP_IPV6M_NODE, &optimal_route_reflection_cmd);
+ install_element(BGP_IPV6L_NODE, &optimal_route_reflection_cmd);
+ install_element(BGP_VPNV4_NODE, &optimal_route_reflection_cmd);
+ install_element(BGP_VPNV6_NODE, &optimal_route_reflection_cmd);
+ install_element(BGP_FLOWSPECV4_NODE, &optimal_route_reflection_cmd);
+ install_element(BGP_FLOWSPECV6_NODE, &optimal_route_reflection_cmd);
+ install_element(BGP_EVPN_NODE, &optimal_route_reflection_cmd);
+
+ /* "neighbor optimal-route-reflection" commands */
+ install_element(BGP_IPV4_NODE, &neighbor_optimal_route_reflection_cmd);
+ install_element(BGP_IPV4M_NODE, &neighbor_optimal_route_reflection_cmd);
+ install_element(BGP_IPV4L_NODE, &neighbor_optimal_route_reflection_cmd);
+ install_element(BGP_IPV6_NODE, &neighbor_optimal_route_reflection_cmd);
+ install_element(BGP_IPV6M_NODE, &neighbor_optimal_route_reflection_cmd);
+ install_element(BGP_IPV6L_NODE, &neighbor_optimal_route_reflection_cmd);
+ install_element(BGP_VPNV4_NODE, &neighbor_optimal_route_reflection_cmd);
+ install_element(BGP_VPNV6_NODE, &neighbor_optimal_route_reflection_cmd);
+ install_element(BGP_FLOWSPECV4_NODE,
+ &neighbor_optimal_route_reflection_cmd);
+ install_element(BGP_FLOWSPECV6_NODE,
+ &neighbor_optimal_route_reflection_cmd);
+ install_element(BGP_EVPN_NODE, &neighbor_optimal_route_reflection_cmd);
+
/* "neighbor route-server" commands.*/
install_element(BGP_NODE, &neighbor_route_server_client_hidden_cmd);
install_element(BGP_NODE, &no_neighbor_route_server_client_hidden_cmd);
@@ -19455,6 +19841,10 @@ void bgp_vty_init(void)
install_element(BGP_EVPN_NODE, &neighbor_allowas_in_cmd);
install_element(BGP_EVPN_NODE, &no_neighbor_allowas_in_cmd);
+ /* neighbor accept-own */
+ install_element(BGP_VPNV4_NODE, &neighbor_accept_own_cmd);
+ install_element(BGP_VPNV6_NODE, &neighbor_accept_own_cmd);
+
/* "neighbor soo" */
install_element(BGP_IPV4_NODE, &neighbor_soo_cmd);
install_element(BGP_IPV4_NODE, &no_neighbor_soo_cmd);
@@ -19590,6 +19980,10 @@ void bgp_vty_init(void)
install_element(BGP_NODE, &neighbor_ttl_security_cmd);
install_element(BGP_NODE, &no_neighbor_ttl_security_cmd);
+ /* "bgp tcp-keepalive" commands */
+ install_element(BGP_NODE, &bgp_tcp_keepalive_cmd);
+ install_element(BGP_NODE, &no_bgp_tcp_keepalive_cmd);
+
/* "show [ip] bgp memory" commands. */
install_element(VIEW_NODE, &show_bgp_memory_cmd);
@@ -19649,6 +20043,8 @@ void bgp_vty_init(void)
install_element(BGP_SRV6_NODE, &no_bgp_srv6_locator_cmd);
install_element(BGP_IPV4_NODE, &af_sid_vpn_export_cmd);
install_element(BGP_IPV6_NODE, &af_sid_vpn_export_cmd);
+ install_element(BGP_NODE, &bgp_sid_vpn_export_cmd);
+ install_element(BGP_NODE, &no_bgp_sid_vpn_export_cmd);
bgp_vty_if_init();
}
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 57a859c61..efdc81a14 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -67,10 +67,13 @@
#include "bgpd/bgp_trace.h"
#include "bgpd/bgp_community.h"
#include "bgpd/bgp_lcommunity.h"
+#include "bgpd/bgp_orr.h"
/* All information about zebra. */
struct zclient *zclient = NULL;
+static int bgp_opaque_msg_handler(ZAPI_CALLBACK_ARGS);
+
/* hook to indicate vrf status change for SNMP */
DEFINE_HOOK(bgp_vrf_status_changed, (struct bgp *bgp, struct interface *ifp),
(bgp, ifp));
@@ -3216,13 +3219,13 @@ static int bgp_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS)
if (strcmp(bgp->srv6_locator_name, chunk->locator_name) != 0) {
zlog_err("%s: Locator name unmatch %s:%s", __func__,
bgp->srv6_locator_name, chunk->locator_name);
- srv6_locator_chunk_free(chunk);
+ srv6_locator_chunk_free(&chunk);
return 0;
}
for (ALL_LIST_ELEMENTS_RO(bgp->srv6_locator_chunks, node, c)) {
if (!prefix_cmp(&c->prefix, &chunk->prefix)) {
- srv6_locator_chunk_free(chunk);
+ srv6_locator_chunk_free(&chunk);
return 0;
}
}
@@ -3255,10 +3258,10 @@ static int bgp_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS)
struct srv6_locator loc = {};
struct bgp *bgp = bgp_get_default();
struct listnode *node, *nnode;
- struct srv6_locator_chunk *chunk;
+ struct srv6_locator_chunk *chunk, *tovpn_sid_locator;
struct bgp_srv6_function *func;
struct bgp *bgp_vrf;
- struct in6_addr *tovpn_sid, *tovpn_sid_locator;
+ struct in6_addr *tovpn_sid;
struct prefix_ipv6 tmp_prefi;
if (zapi_srv6_locator_decode(zclient->ibuf, &loc) < 0)
@@ -3269,7 +3272,7 @@ static int bgp_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS)
if (prefix_match((struct prefix *)&loc.prefix,
(struct prefix *)&chunk->prefix)) {
listnode_delete(bgp->srv6_locator_chunks, chunk);
- srv6_locator_chunk_free(chunk);
+ srv6_locator_chunk_free(&chunk);
}
// refresh functions
@@ -3312,6 +3315,17 @@ static int bgp_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS)
XFREE(MTYPE_BGP_SRV6_SID,
bgp_vrf->vpn_policy[AFI_IP6].tovpn_sid);
}
+
+ /* refresh per-vrf tovpn_sid */
+ tovpn_sid = bgp_vrf->tovpn_sid;
+ if (tovpn_sid) {
+ tmp_prefi.family = AF_INET6;
+ tmp_prefi.prefixlen = IPV6_MAX_BITLEN;
+ tmp_prefi.prefix = *tovpn_sid;
+ if (prefix_match((struct prefix *)&loc.prefix,
+ (struct prefix *)&tmp_prefi))
+ XFREE(MTYPE_BGP_SRV6_SID, bgp_vrf->tovpn_sid);
+ }
}
vpn_leak_postchange_all();
@@ -3327,10 +3341,12 @@ static int bgp_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS)
if (tovpn_sid_locator) {
tmp_prefi.family = AF_INET6;
tmp_prefi.prefixlen = IPV6_MAX_BITLEN;
- tmp_prefi.prefix = *tovpn_sid_locator;
+ tmp_prefi.prefix = tovpn_sid_locator->prefix.prefix;
if (prefix_match((struct prefix *)&loc.prefix,
(struct prefix *)&tmp_prefi))
- XFREE(MTYPE_BGP_SRV6_SID, tovpn_sid_locator);
+ srv6_locator_chunk_free(
+ &bgp_vrf->vpn_policy[AFI_IP]
+ .tovpn_sid_locator);
}
/* refresh vpnv6 tovpn_sid_locator */
@@ -3339,10 +3355,24 @@ static int bgp_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS)
if (tovpn_sid_locator) {
tmp_prefi.family = AF_INET6;
tmp_prefi.prefixlen = IPV6_MAX_BITLEN;
- tmp_prefi.prefix = *tovpn_sid_locator;
+ tmp_prefi.prefix = tovpn_sid_locator->prefix.prefix;
if (prefix_match((struct prefix *)&loc.prefix,
(struct prefix *)&tmp_prefi))
- XFREE(MTYPE_BGP_SRV6_SID, tovpn_sid_locator);
+ srv6_locator_chunk_free(
+ &bgp_vrf->vpn_policy[AFI_IP6]
+ .tovpn_sid_locator);
+ }
+
+ /* refresh per-vrf tovpn_sid_locator */
+ tovpn_sid_locator = bgp_vrf->tovpn_sid_locator;
+ if (tovpn_sid_locator) {
+ tmp_prefi.family = AF_INET6;
+ tmp_prefi.prefixlen = IPV6_MAX_BITLEN;
+ tmp_prefi.prefix = tovpn_sid_locator->prefix.prefix;
+ if (prefix_match((struct prefix *)&loc.prefix,
+ (struct prefix *)&tmp_prefi))
+ srv6_locator_chunk_free(
+ &bgp_vrf->tovpn_sid_locator);
}
}
@@ -3382,6 +3412,7 @@ static zclient_handler *const bgp_handlers[] = {
[ZEBRA_SRV6_LOCATOR_DELETE] = bgp_zebra_process_srv6_locator_delete,
[ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK] =
bgp_zebra_process_srv6_locator_chunk,
+ [ZEBRA_OPAQUE_MESSAGE] = bgp_opaque_msg_handler,
};
static int bgp_if_new_hook(struct interface *ifp)
@@ -3836,3 +3867,34 @@ int bgp_zebra_srv6_manager_release_locator_chunk(const char *name)
{
return srv6_manager_release_locator_chunk(zclient, name);
}
+
+/*
+ * ORR messages between processes
+ */
+static int bgp_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
+{
+ struct stream *s;
+ struct zapi_opaque_msg info;
+ struct orr_igp_metric_info table;
+ int ret = 0;
+
+ s = zclient->ibuf;
+
+ if (zclient_opaque_decode(s, &info) != 0) {
+ bgp_orr_debug("%s: opaque decode failed", __func__);
+ return -1;
+ }
+
+ switch (info.type) {
+ case ORR_IGP_METRIC_UPDATE:
+ STREAM_GET(&table, s, sizeof(table));
+ ret = bgg_orr_message_process(BGP_ORR_IMSG_IGP_METRIC_UPDATE,
+ (void *)&table);
+ break;
+ default:
+ break;
+ }
+
+stream_failure:
+ return ret;
+}
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 5a9ec1bbd..6ad1cf2c0 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -92,6 +92,7 @@
#include "bgpd/bgp_evpn_private.h"
#include "bgpd/bgp_evpn_mh.h"
#include "bgpd/bgp_mac.h"
+#include "bgpd/bgp_orr.h"
DEFINE_MTYPE_STATIC(BGPD, PEER_TX_SHUTDOWN_MSG, "Peer shutdown message (TX)");
DEFINE_MTYPE_STATIC(BGPD, BGP_EVPN_INFO, "BGP EVPN instance information");
@@ -551,6 +552,21 @@ void bgp_timers_unset(struct bgp *bgp)
bgp->default_delayopen = BGP_DEFAULT_DELAYOPEN;
}
+void bgp_tcp_keepalive_set(struct bgp *bgp, uint16_t keepalive_idle,
+ uint16_t keepalive_intvl, uint16_t keepalive_probes)
+{
+ bgp->tcp_keepalive_idle = keepalive_idle;
+ bgp->tcp_keepalive_intvl = keepalive_intvl;
+ bgp->tcp_keepalive_probes = keepalive_probes;
+}
+
+void bgp_tcp_keepalive_unset(struct bgp *bgp)
+{
+ bgp->tcp_keepalive_idle = 0;
+ bgp->tcp_keepalive_intvl = 0;
+ bgp->tcp_keepalive_probes = 0;
+}
+
/* BGP confederation configuration. */
void bgp_confederation_id_set(struct bgp *bgp, as_t as)
{
@@ -1111,6 +1127,8 @@ static void peer_free(struct peer *peer)
bgp_timer_set(peer);
bgp_reads_off(peer);
bgp_writes_off(peer);
+ FOREACH_AFI_SAFI (afi, safi)
+ THREAD_OFF(peer->t_revalidate_all[afi][safi]);
assert(!peer->t_write);
assert(!peer->t_read);
BGP_EVENT_FLUSH(peer);
@@ -1824,6 +1842,8 @@ bool bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi)
/* Change peer's AS number. */
void peer_as_change(struct peer *peer, as_t as, int as_specified)
{
+ afi_t afi;
+ safi_t safi;
enum bgp_peer_sort origtype, newtype;
/* Stop peer. */
@@ -1862,6 +1882,11 @@ void peer_as_change(struct peer *peer, as_t as, int as_specified)
/* reflector-client reset */
if (newtype != BGP_PEER_IBGP) {
+
+ FOREACH_AFI_SAFI (afi, safi)
+ UNSET_FLAG(peer->af_flags[afi][safi],
+ PEER_FLAG_ORR_GROUP);
+
UNSET_FLAG(peer->af_flags[AFI_IP][SAFI_UNICAST],
PEER_FLAG_REFLECTOR_CLIENT);
UNSET_FLAG(peer->af_flags[AFI_IP][SAFI_MULTICAST],
@@ -2421,6 +2446,8 @@ int peer_delete(struct peer *peer)
bgp_keepalives_off(peer);
bgp_reads_off(peer);
bgp_writes_off(peer);
+ FOREACH_AFI_SAFI (afi, safi)
+ THREAD_OFF(peer->t_revalidate_all[afi][safi]);
assert(!CHECK_FLAG(peer->thread_flags, PEER_THREAD_WRITES_ON));
assert(!CHECK_FLAG(peer->thread_flags, PEER_THREAD_READS_ON));
assert(!CHECK_FLAG(peer->thread_flags, PEER_THREAD_KEEPALIVES_ON));
@@ -3182,6 +3209,7 @@ static struct bgp *bgp_create(as_t *as, const char *name,
bgp->default_local_pref = BGP_DEFAULT_LOCAL_PREF;
bgp->default_subgroup_pkt_queue_max =
BGP_DEFAULT_SUBGROUP_PKT_QUEUE_MAX;
+ bgp_tcp_keepalive_unset(bgp);
bgp_timers_unset(bgp);
bgp->default_min_holdtime = 0;
bgp->restart_time = BGP_DEFAULT_RESTART_TIME;
@@ -3617,6 +3645,9 @@ int bgp_delete(struct bgp *bgp)
hook_call(bgp_inst_delete, bgp);
+ FOREACH_AFI_SAFI (afi, safi)
+ THREAD_OFF(bgp->t_revalidate[afi][safi]);
+
THREAD_OFF(bgp->t_condition_check);
THREAD_OFF(bgp->t_startup);
THREAD_OFF(bgp->t_maxmed_onstartup);
@@ -3834,6 +3865,8 @@ void bgp_free(struct bgp *bgp)
ecommunity_free(&bgp->vpn_policy[afi].rtlist[dir]);
}
+ bgp_orr_cleanup(bgp);
+
XFREE(MTYPE_BGP, bgp->name);
XFREE(MTYPE_BGP, bgp->name_pretty);
XFREE(MTYPE_BGP, bgp->snmp_stats);
@@ -4246,15 +4279,16 @@ static const struct peer_flag_action peer_flag_action_list[] = {
{PEER_FLAG_TIMER_CONNECT, 0, peer_change_none},
{PEER_FLAG_TIMER_DELAYOPEN, 0, peer_change_none},
{PEER_FLAG_PASSWORD, 0, peer_change_none},
- {PEER_FLAG_LOCAL_AS, 0, peer_change_none},
- {PEER_FLAG_LOCAL_AS_NO_PREPEND, 0, peer_change_none},
- {PEER_FLAG_LOCAL_AS_REPLACE_AS, 0, peer_change_none},
+ {PEER_FLAG_LOCAL_AS, 0, peer_change_reset},
+ {PEER_FLAG_LOCAL_AS_NO_PREPEND, 0, peer_change_reset},
+ {PEER_FLAG_LOCAL_AS_REPLACE_AS, 0, peer_change_reset},
{PEER_FLAG_UPDATE_SOURCE, 0, peer_change_none},
{PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE, 0, peer_change_none},
{PEER_FLAG_EXTENDED_OPT_PARAMS, 0, peer_change_reset},
{PEER_FLAG_ROLE_STRICT_MODE, 0, peer_change_reset},
{PEER_FLAG_ROLE, 0, peer_change_reset},
{PEER_FLAG_PORT, 0, peer_change_reset},
+ {PEER_FLAG_AIGP, 0, peer_change_none},
{0, 0, 0}};
static const struct peer_flag_action peer_af_flag_action_list[] = {
@@ -4287,6 +4321,7 @@ static const struct peer_flag_action peer_af_flag_action_list[] = {
{PEER_FLAG_WEIGHT, 0, peer_change_reset_in},
{PEER_FLAG_DISABLE_ADDPATH_RX, 0, peer_change_reset},
{PEER_FLAG_SOO, 0, peer_change_reset},
+ {PEER_FLAG_ACCEPT_OWN, 0, peer_change_reset},
{0, 0, 0}};
/* Proper action set. */
@@ -4617,6 +4652,11 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi,
if (flag & PEER_FLAG_REFLECTOR_CLIENT && ptype != BGP_PEER_IBGP)
return BGP_ERR_NOT_INTERNAL_PEER;
+ /* Do not remove reflector client when ORR is configured on this peer */
+ if (flag & PEER_FLAG_REFLECTOR_CLIENT && !set &&
+ peer_orr_rrclient_check(peer, afi, safi))
+ return BGP_ERR_PEER_ORR_CONFIGURED;
+
/* Special check for remove-private-AS. */
if (flag & PEER_FLAG_REMOVE_PRIVATE_AS && ptype == BGP_PEER_IBGP)
return BGP_ERR_REMOVE_PRIVATE_AS;
@@ -5484,11 +5524,11 @@ void peer_on_policy_change(struct peer *peer, afi_t afi, safi_t safi,
if (!peer_established(peer))
return;
- if (CHECK_FLAG(peer->af_flags[afi][safi],
- PEER_FLAG_SOFT_RECONFIG)) {
- bgp_soft_reconfig_in(peer, afi, safi);
- } else if (CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_OLD_RCV) ||
- CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_NEW_RCV)) {
+ if (bgp_soft_reconfig_in(peer, afi, safi))
+ return;
+
+ if (CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_OLD_RCV) ||
+ CHECK_FLAG(peer->cap, PEER_CAP_REFRESH_NEW_RCV)) {
if (CHECK_FLAG(peer->af_cap[afi][safi],
PEER_CAP_ORF_PREFIX_SM_ADV) &&
(CHECK_FLAG(peer->af_cap[afi][safi],
@@ -6128,18 +6168,8 @@ int peer_local_as_set(struct peer *peer, as_t as, bool no_prepend,
(void)peer_sort(peer);
/* Check if handling a regular peer. */
- if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
- /* Send notification or reset peer depending on state. */
- if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) {
- peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE;
- bgp_notify_send(peer, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- } else
- bgp_session_reset(peer);
-
- /* Skip peer-group mechanics for regular peers. */
+ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
return 0;
- }
/*
* Set flag and configuration on all peer-group members, unless they are
@@ -6168,14 +6198,6 @@ int peer_local_as_set(struct peer *peer, as_t as, bool no_prepend,
COND_FLAG(member->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS,
replace_as);
member->change_local_as = as;
-
- /* Send notification or stop peer depending on state. */
- if (BGP_IS_VALID_STATE_FOR_NOTIF(member->status)) {
- member->last_reset = PEER_DOWN_LOCAL_AS_CHANGE;
- bgp_notify_send(member, BGP_NOTIFY_CEASE,
- BGP_NOTIFY_CEASE_CONFIG_CHANGE);
- } else
- BGP_EVENT_ADD(member, BGP_Stop);
}
return 0;
@@ -7762,10 +7784,7 @@ int peer_clear_soft(struct peer *peer, afi_t afi, safi_t safi,
|| stype == BGP_CLEAR_SOFT_IN_ORF_PREFIX) {
/* If neighbor has soft reconfiguration inbound flag.
Use Adj-RIB-In database. */
- if (CHECK_FLAG(peer->af_flags[afi][safi],
- PEER_FLAG_SOFT_RECONFIG))
- bgp_soft_reconfig_in(peer, afi, safi);
- else {
+ if (!bgp_soft_reconfig_in(peer, afi, safi)) {
/* If neighbor has route refresh capability, send route
refresh
message to the peer. */
@@ -7854,6 +7873,7 @@ void bgp_master_init(struct thread_master *master, const int buffer_size,
bm->socket_buffer = buffer_size;
bm->wait_for_fib = false;
bm->tcp_dscp = IPTOS_PREC_INTERNETCONTROL;
+ bm->inq_limit = BM_DEFAULT_INQ_LIMIT;
bgp_mac_init();
/* init the rd id space.
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index c8bcb5cd5..8a0ec5ad2 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -47,6 +47,7 @@
#include "bgp_io.h"
#include "lib/bfd.h"
+#include "lib/orr_msg.h"
#define BGP_MAX_HOSTNAME 64 /* Linux max, is larger than most other sys */
#define BGP_PEER_MAX_HASH_SIZE 16384
@@ -132,6 +133,7 @@ struct bgp_master {
/* Various BGP global configuration. */
uint8_t options;
+
#define BGP_OPT_NO_FIB (1 << 0)
#define BGP_OPT_NO_LISTEN (1 << 1)
#define BGP_OPT_NO_ZEBRA (1 << 2)
@@ -175,6 +177,9 @@ struct bgp_master {
/* DSCP value for TCP sessions */
uint8_t tcp_dscp;
+#define BM_DEFAULT_INQ_LIMIT 10000
+ uint32_t inq_limit;
+
QOBJ_FIELDS;
};
DECLARE_QOBJ_TYPE(bgp_master);
@@ -196,6 +201,40 @@ struct bgp_redist {
struct bgp_rmap rmap;
};
+struct bgp_orr_igp_metric {
+ struct prefix prefix;
+ uint32_t igp_metric;
+};
+
+struct bgp_orr_group {
+ /* Name of this ORR group */
+ char *name;
+
+ /* Address Family Identifiers */
+ afi_t afi;
+ safi_t safi;
+
+ /* Pointer to BGP */
+ struct bgp *bgp;
+
+ /* Root Routers of the group */
+ struct peer *primary;
+ struct peer *secondary;
+ struct peer *tertiary;
+
+ /* Active Root Router of the group */
+ struct peer *active;
+
+ /* RR clients belong to this group */
+ struct list *rr_client_list;
+
+ /* IGP metric data from active root */
+ struct list *igp_metric_info;
+
+ /* Route table calculated from active root for this group */
+ struct bgp_table *route_table;
+};
+
enum vpn_policy_direction {
BGP_VPN_POLICY_DIR_FROMVPN = 0,
BGP_VPN_POLICY_DIR_TOVPN = 1,
@@ -238,7 +277,7 @@ struct vpn_policy {
*/
uint32_t tovpn_sid_index; /* unset => set to 0 */
struct in6_addr *tovpn_sid;
- struct in6_addr *tovpn_sid_locator;
+ struct srv6_locator_chunk *tovpn_sid_locator;
uint32_t tovpn_sid_transpose_label;
struct in6_addr *tovpn_zebra_vrf_sid_last_sent;
};
@@ -431,6 +470,8 @@ struct bgp {
/* BGP update delay on startup */
struct thread *t_update_delay;
struct thread *t_establish_wait;
+ struct thread *t_revalidate[AFI_MAX][SAFI_MAX];
+
uint8_t update_delay_over;
uint8_t main_zebra_update_hold;
uint8_t main_peers_update_hold;
@@ -458,44 +499,46 @@ struct bgp {
/* BGP flags. */
uint64_t flags;
-#define BGP_FLAG_ALWAYS_COMPARE_MED (1 << 0)
-#define BGP_FLAG_DETERMINISTIC_MED (1 << 1)
-#define BGP_FLAG_MED_MISSING_AS_WORST (1 << 2)
-#define BGP_FLAG_MED_CONFED (1 << 3)
-#define BGP_FLAG_NO_CLIENT_TO_CLIENT (1 << 4)
-#define BGP_FLAG_COMPARE_ROUTER_ID (1 << 5)
-#define BGP_FLAG_ASPATH_IGNORE (1 << 6)
-#define BGP_FLAG_IMPORT_CHECK (1 << 7)
-#define BGP_FLAG_NO_FAST_EXT_FAILOVER (1 << 8)
-#define BGP_FLAG_LOG_NEIGHBOR_CHANGES (1 << 9)
+#define BGP_FLAG_ALWAYS_COMPARE_MED (1ULL << 0)
+#define BGP_FLAG_DETERMINISTIC_MED (1ULL << 1)
+#define BGP_FLAG_MED_MISSING_AS_WORST (1ULL << 2)
+#define BGP_FLAG_MED_CONFED (1ULL << 3)
+#define BGP_FLAG_NO_CLIENT_TO_CLIENT (1ULL << 4)
+#define BGP_FLAG_COMPARE_ROUTER_ID (1ULL << 5)
+#define BGP_FLAG_ASPATH_IGNORE (1ULL << 6)
+#define BGP_FLAG_IMPORT_CHECK (1ULL << 7)
+#define BGP_FLAG_NO_FAST_EXT_FAILOVER (1ULL << 8)
+#define BGP_FLAG_LOG_NEIGHBOR_CHANGES (1ULL << 9)
/* This flag is set when we have full BGP Graceful-Restart mode enable */
-#define BGP_FLAG_GRACEFUL_RESTART (1 << 10)
-
-#define BGP_FLAG_ASPATH_CONFED (1 << 11)
-#define BGP_FLAG_ASPATH_MULTIPATH_RELAX (1 << 12)
-#define BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY (1 << 13)
-#define BGP_FLAG_DISABLE_NH_CONNECTED_CHK (1 << 14)
-#define BGP_FLAG_MULTIPATH_RELAX_AS_SET (1 << 15)
-#define BGP_FLAG_FORCE_STATIC_PROCESS (1 << 16)
-#define BGP_FLAG_SHOW_HOSTNAME (1 << 17)
-#define BGP_FLAG_GR_PRESERVE_FWD (1 << 18)
-#define BGP_FLAG_GRACEFUL_SHUTDOWN (1 << 19)
-#define BGP_FLAG_DELETE_IN_PROGRESS (1 << 20)
-#define BGP_FLAG_SELECT_DEFER_DISABLE (1 << 21)
-#define BGP_FLAG_GR_DISABLE_EOR (1 << 22)
-#define BGP_FLAG_EBGP_REQUIRES_POLICY (1 << 23)
-#define BGP_FLAG_SHOW_NEXTHOP_HOSTNAME (1 << 24)
+#define BGP_FLAG_GRACEFUL_RESTART (1ULL << 10)
+
+#define BGP_FLAG_ASPATH_CONFED (1ULL << 11)
+#define BGP_FLAG_ASPATH_MULTIPATH_RELAX (1ULL << 12)
+#define BGP_FLAG_RR_ALLOW_OUTBOUND_POLICY (1ULL << 13)
+#define BGP_FLAG_DISABLE_NH_CONNECTED_CHK (1ULL << 14)
+#define BGP_FLAG_MULTIPATH_RELAX_AS_SET (1ULL << 15)
+#define BGP_FLAG_FORCE_STATIC_PROCESS (1ULL << 16)
+#define BGP_FLAG_SHOW_HOSTNAME (1ULL << 17)
+#define BGP_FLAG_GR_PRESERVE_FWD (1ULL << 18)
+#define BGP_FLAG_GRACEFUL_SHUTDOWN (1ULL << 19)
+#define BGP_FLAG_DELETE_IN_PROGRESS (1ULL << 20)
+#define BGP_FLAG_SELECT_DEFER_DISABLE (1ULL << 21)
+#define BGP_FLAG_GR_DISABLE_EOR (1ULL << 22)
+#define BGP_FLAG_EBGP_REQUIRES_POLICY (1ULL << 23)
+#define BGP_FLAG_SHOW_NEXTHOP_HOSTNAME (1ULL << 24)
/* This flag is set if the instance is in administrative shutdown */
-#define BGP_FLAG_SHUTDOWN (1 << 25)
-#define BGP_FLAG_SUPPRESS_FIB_PENDING (1 << 26)
-#define BGP_FLAG_SUPPRESS_DUPLICATES (1 << 27)
-#define BGP_FLAG_PEERTYPE_MULTIPATH_RELAX (1 << 29)
+#define BGP_FLAG_SHUTDOWN (1ULL << 25)
+#define BGP_FLAG_SUPPRESS_FIB_PENDING (1ULL << 26)
+#define BGP_FLAG_SUPPRESS_DUPLICATES (1ULL << 27)
+#define BGP_FLAG_PEERTYPE_MULTIPATH_RELAX (1ULL << 29)
/* Indicate Graceful Restart support for BGP NOTIFICATION messages */
-#define BGP_FLAG_GRACEFUL_NOTIFICATION (1 << 30)
+#define BGP_FLAG_GRACEFUL_NOTIFICATION (1ULL << 30)
/* Send Hard Reset CEASE Notification for 'Administrative Reset' */
-#define BGP_FLAG_HARD_ADMIN_RESET (1 << 31)
+#define BGP_FLAG_HARD_ADMIN_RESET (1ULL << 31)
+/* Evaluate the AIGP attribute during the best path selection process */
+#define BGP_FLAG_COMPARE_AIGP (1ULL << 32)
/* BGP default address-families.
* New peers inherit enabled afi/safis from bgp instance.
@@ -719,8 +762,12 @@ struct bgp {
#define BGP_VRF_AUTO (1 << 0)
#define BGP_VRF_IMPORT_RT_CFGD (1 << 1)
#define BGP_VRF_EXPORT_RT_CFGD (1 << 2)
-#define BGP_VRF_RD_CFGD (1 << 3)
-#define BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY (1 << 4)
+#define BGP_VRF_IMPORT_AUTO_RT_CFGD (1 << 3) /* retain auto when cfgd */
+#define BGP_VRF_EXPORT_AUTO_RT_CFGD (1 << 4) /* retain auto when cfgd */
+#define BGP_VRF_RD_CFGD (1 << 5)
+#define BGP_VRF_L3VNI_PREFIX_ROUTES_ONLY (1 << 6)
+/* per-VRF toVPN SID */
+#define BGP_VRF_TOVPN_SID_AUTO (1 << 7)
/* unique ID for auto derivation of RD for this vrf */
uint16_t vrf_rd_id;
@@ -768,12 +815,26 @@ struct bgp {
char srv6_locator_name[SRV6_LOCNAME_SIZE];
struct list *srv6_locator_chunks;
struct list *srv6_functions;
+ uint32_t tovpn_sid_index; /* unset => set to 0 */
+ struct in6_addr *tovpn_sid;
+ struct srv6_locator_chunk *tovpn_sid_locator;
+ uint32_t tovpn_sid_transpose_label;
+ struct in6_addr *tovpn_zebra_vrf_sid_last_sent;
+
+ /* TCP keepalive parameters for BGP connection */
+ uint16_t tcp_keepalive_idle;
+ uint16_t tcp_keepalive_intvl;
+ uint16_t tcp_keepalive_probes;
struct timeval ebgprequirespolicywarning;
#define FIFTEENMINUTE2USEC (int64_t)15 * 60 * 1000000
bool allow_martian;
+ /* BGP optimal route reflection group and Root Router configuration */
+ uint32_t orr_group_count;
+ struct list *orr_group[AFI_MAX][SAFI_MAX];
+
QOBJ_FIELDS;
};
DECLARE_QOBJ_TYPE(bgp);
@@ -1351,6 +1412,7 @@ struct peer {
/* `local-role` configured */
#define PEER_FLAG_ROLE (1ULL << 32)
#define PEER_FLAG_PORT (1ULL << 33)
+#define PEER_FLAG_AIGP (1ULL << 34)
/*
*GR-Disabled mode means unset PEER_FLAG_GRACEFUL_RESTART
@@ -1417,6 +1479,11 @@ struct peer {
#define PEER_FLAG_MAX_PREFIX_FORCE (1ULL << 28)
#define PEER_FLAG_DISABLE_ADDPATH_RX (1ULL << 29)
#define PEER_FLAG_SOO (1ULL << 30)
+#define PEER_FLAG_ORR_GROUP (1ULL << 31) /* Optimal-Route-Reflection */
+#define PEER_FLAG_ACCEPT_OWN (1ULL << 32)
+
+ /* BGP Optimal Route Reflection Group name */
+ char *orr_group_name[AFI_MAX][SAFI_MAX];
enum bgp_addpath_strat addpath_type[AFI_MAX][SAFI_MAX];
@@ -1457,6 +1524,7 @@ struct peer {
/* LLGR aware peer */
#define PEER_STATUS_LLGR_WAIT (1U << 11)
#define PEER_STATUS_REFRESH_PENDING (1U << 12) /* refresh request from peer */
+#define PEER_STATUS_RTT_SHUTDOWN (1U << 13) /* In shutdown state due to RTT */
/* Configured timer values. */
_Atomic uint32_t holdtime;
@@ -1489,6 +1557,7 @@ struct peer {
struct thread *t_gr_restart;
struct thread *t_gr_stale;
struct thread *t_llgr_stale[AFI_MAX][SAFI_MAX];
+ struct thread *t_revalidate_all[AFI_MAX][SAFI_MAX];
struct thread *t_generate_updgrp_packets;
struct thread *t_process_packet;
struct thread *t_process_packet_error;
@@ -1669,6 +1738,7 @@ struct peer {
#define PEER_DOWN_WAITING_OPEN 32U /* Waiting for open to succeed */
#define PEER_DOWN_PFX_COUNT 33U /* Reached received prefix count */
#define PEER_DOWN_SOCKET_ERROR 34U /* Some socket error happened */
+#define PEER_DOWN_RTT_SHUTDOWN 35U /* Automatically shutdown due to RTT */
/*
* Remember to update peer_down_str in bgp_fsm.c when you add
* a new value to the last_reset reason
@@ -1839,6 +1909,7 @@ struct bgp_nlri {
#define BGP_ATTR_PMSI_TUNNEL 22
#define BGP_ATTR_ENCAP 23
#define BGP_ATTR_IPV6_EXT_COMMUNITIES 25
+#define BGP_ATTR_AIGP 26
#define BGP_ATTR_LARGE_COMMUNITIES 32
#define BGP_ATTR_OTC 35
#define BGP_ATTR_PREFIX_SID 40
@@ -1967,6 +2038,13 @@ struct bgp_nlri {
#define BGP_DYNAMIC_NEIGHBORS_LIMIT_MIN 1
#define BGP_DYNAMIC_NEIGHBORS_LIMIT_MAX 65535
+/* BGP AIGP */
+#define BGP_AIGP_TLV_RESERVED 0 /* AIGP Reserved */
+#define BGP_AIGP_TLV_METRIC 1 /* AIGP Metric */
+#define BGP_AIGP_TLV_METRIC_LEN 11
+#define BGP_AIGP_TLV_METRIC_MAX 0xffffffffffffffffULL
+#define BGP_AIGP_TLV_METRIC_DESC "Accumulated IGP Metric"
+
/* Flag for peer_clear_soft(). */
enum bgp_clear_type {
BGP_CLEAR_SOFT_NONE,
@@ -2024,7 +2102,10 @@ enum bgp_create_error_code {
/*BGP Open Policy ERRORS */
BGP_ERR_INVALID_ROLE_NAME = -35,
- BGP_ERR_INVALID_INTERNAL_ROLE = -36
+ BGP_ERR_INVALID_INTERNAL_ROLE = -36,
+
+ /* BGP ORR ERRORS */
+ BGP_ERR_PEER_ORR_CONFIGURED = -37,
};
/*
@@ -2076,6 +2157,7 @@ extern struct peer_group *peer_group_lookup_dynamic_neighbor(struct bgp *,
extern struct peer *peer_lookup_dynamic_neighbor(struct bgp *,
union sockunion *);
+extern bool peer_orr_rrclient_check(struct peer *peer, afi_t afi, safi_t safi);
/*
* Peers are incredibly easy to memory leak
* due to the various ways that they are actually used
@@ -2213,6 +2295,9 @@ extern int peer_default_originate_set(struct peer *peer, afi_t afi, safi_t safi,
const char *rmap,
struct route_map *route_map);
extern int peer_default_originate_unset(struct peer *, afi_t, safi_t);
+extern void bgp_tcp_keepalive_set(struct bgp *bgp, uint16_t idle,
+ uint16_t interval, uint16_t probes);
+extern void bgp_tcp_keepalive_unset(struct bgp *bgp);
extern void peer_port_set(struct peer *, uint16_t);
extern void peer_port_unset(struct peer *);
@@ -2323,6 +2408,12 @@ extern void bgp_shutdown_disable(struct bgp *bgp);
extern void bgp_close(void);
extern void bgp_free(struct bgp *);
void bgp_gr_apply_running_config(void);
+extern int bgp_afi_safi_orr_group_set(struct bgp *bgp, afi_t afi, safi_t safi,
+ const char *name, struct peer *primary,
+ struct peer *secondary,
+ struct peer *tertiary);
+extern int bgp_afi_safi_orr_group_unset(struct bgp *bgp, afi_t afi, safi_t safi,
+ const char *name);
/* BGP GR */
int bgp_global_gr_init(struct bgp *bgp);
diff --git a/bgpd/rfapi/rfapi.c b/bgpd/rfapi/rfapi.c
index ed0714ce2..a5d57748b 100644
--- a/bgpd/rfapi/rfapi.c
+++ b/bgpd/rfapi/rfapi.c
@@ -3174,13 +3174,17 @@ DEFUN (debug_rfapi_unregister_vn_un,
"debug rfapi-dev unregister vn <A.B.C.D|X:X::X:X> un <A.B.C.D|X:X::X:X> prefix <A.B.C.D/M|X:X::X:X/M> [kill]",
DEBUG_STR
DEBUG_RFAPI_STR
- "rfapi_register\n"
+ "rfapi_unregister\n"
"indicate vn addr follows\n"
"virtual network interface address\n"
+ "virtual network interface address\n"
"indicate xt addr follows\n"
"underlay network interface address\n"
+ "underlay network interface address\n"
"prefix to remove\n"
- "Remove without holddown")
+ "prefix to remove\n"
+ "prefix to remove\n"
+ "Remove without holddown\n")
{
struct rfapi_ip_addr vn;
struct rfapi_ip_addr un;
@@ -3195,7 +3199,6 @@ DEFUN (debug_rfapi_unregister_vn_un,
if ((rc = rfapiCliGetRfapiIpAddr(vty, argv[4]->arg, &vn)))
return rc;
-
/*
* Get UN addr
*/
diff --git a/bgpd/subdir.am b/bgpd/subdir.am
index b1eeb937e..04fe1f124 100644
--- a/bgpd/subdir.am
+++ b/bgpd/subdir.am
@@ -6,36 +6,9 @@ if BGPD
noinst_LIBRARIES += bgpd/libbgp.a
sbin_PROGRAMS += bgpd/bgpd
noinst_PROGRAMS += bgpd/bgp_btoa
-vtysh_scan += \
- bgpd/bgp_bfd.c \
- bgpd/bgp_debug.c \
- bgpd/bgp_dump.c \
- bgpd/bgp_evpn_mh.c \
- bgpd/bgp_evpn_vty.c \
- bgpd/bgp_filter.c \
- bgpd/bgp_labelpool.c \
- bgpd/bgp_mplsvpn.c \
- bgpd/bgp_nexthop.c \
- bgpd/bgp_route.c \
- bgpd/bgp_routemap.c \
- bgpd/bgp_vty.c \
- bgpd/bgp_flowspec_vty.c \
- # end
-
-# can be loaded as DSO - always include for vtysh
-vtysh_scan += bgpd/bgp_rpki.c
-vtysh_scan += bgpd/bgp_bmp.c
vtysh_daemons += bgpd
-if ENABLE_BGP_VNC
-vtysh_scan += \
- bgpd/rfapi/bgp_rfapi_cfg.c \
- bgpd/rfapi/rfapi.c \
- bgpd/rfapi/rfapi_vty.c \
- bgpd/rfapi/vnc_debug.c \
- # end
-endif
if SNMP
module_LTLIBRARIES += bgpd/bgpd_snmp.la
endif
@@ -103,6 +76,7 @@ bgpd_libbgp_a_SOURCES = \
bgpd/bgp_vty.c \
bgpd/bgp_zebra.c \
bgpd/bgpd.c \
+ bgpd/bgp_orr.c \
bgpd/bgp_trace.c \
# end
@@ -183,6 +157,7 @@ noinst_HEADERS += \
bgpd/bgp_vty.h \
bgpd/bgp_zebra.h \
bgpd/bgpd.h \
+ bgpd/bgp_orr.h \
bgpd/bgp_trace.h \
\
bgpd/rfapi/bgp_rfapi_cfg.h \
diff --git a/configure.ac b/configure.ac
index 4e1080045..97c8ca451 100644
--- a/configure.ac
+++ b/configure.ac
@@ -712,6 +712,8 @@ AC_ARG_ENABLE([cpu-time],
AS_HELP_STRING([--disable-cpu-time], [disable cpu usage data gathering]))
AC_ARG_ENABLE([pcreposix],
AS_HELP_STRING([--enable-pcreposix], [enable using PCRE Posix libs for regex functions]))
+AC_ARG_ENABLE([pcre2posix],
+ AS_HELP_STRING([--enable-pcre2posix], [enable using PCRE2 Posix libs for regex functions]))
AC_ARG_ENABLE([fpm],
AS_HELP_STRING([--enable-fpm], [enable Forwarding Plane Manager support]))
AC_ARG_ENABLE([werror],
@@ -1659,6 +1661,16 @@ if test "$enable_pcreposix" = "yes"; then
fi
AC_SUBST([HAVE_LIBPCREPOSIX])
+dnl ---------------------------
+dnl check system has PCRE2 regexp
+dnl ---------------------------
+if test "$enable_pcre2posix" = "yes"; then
+ AC_CHECK_LIB([pcre2-posix], [regexec], [], [
+ AC_MSG_ERROR([--enable-pcre2posix given but unable to find libpcre2-posix])
+ ])
+fi
+AC_SUBST([HAVE_LIBPCRE2_POSIX])
+
dnl ##########################################################################
dnl test "$enable_clippy_only" != "yes"
fi
@@ -2631,6 +2643,7 @@ AC_DEFINE_UNQUOTED([ZEBRA_SERV_PATH], ["$frr_statedir%s%s/zserv.api"], [zebra ap
AC_DEFINE_UNQUOTED([BFDD_CONTROL_SOCKET], ["$frr_statedir%s%s/bfdd.sock"], [bfdd control socket])
AC_DEFINE_UNQUOTED([OSPFD_GR_STATE], ["$frr_statedir%s/ospfd-gr.json"], [ospfd GR state information])
AC_DEFINE_UNQUOTED([OSPF6D_GR_STATE], ["$frr_statedir/ospf6d-gr.json"], [ospf6d GR state information])
+AC_DEFINE_UNQUOTED([ISISD_RESTART], ["$frr_statedir%s/isid-restart.json"], [isisd restart information])
AC_DEFINE_UNQUOTED([OSPF6_AUTH_SEQ_NUM_FILE], ["$frr_statedir/ospf6d-at-seq-no.dat"], [ospf6d AT Sequence number information])
AC_DEFINE_UNQUOTED([DAEMON_VTY_DIR], ["$frr_statedir%s%s"], [daemon vty directory])
AC_DEFINE_UNQUOTED([DAEMON_DB_DIR], ["$frr_statedir"], [daemon database directory])
@@ -2746,7 +2759,6 @@ AC_CONFIG_FILES([
pkgsrc/ripd.sh pkgsrc/ripngd.sh pkgsrc/zebra.sh
pkgsrc/eigrpd.sh])
-AC_CONFIG_FILES([vtysh/extract.pl], [chmod +x vtysh/extract.pl])
AC_CONFIG_FILES([tools/frr], [chmod +x tools/frr])
AC_CONFIG_FILES([tools/watchfrr.sh], [chmod +x tools/watchfrr.sh])
AC_CONFIG_FILES([tools/frrinit.sh], [chmod +x tools/frrinit.sh])
diff --git a/debian/frr.install b/debian/frr.install
index 48263222f..044b48498 100644
--- a/debian/frr.install
+++ b/debian/frr.install
@@ -1,6 +1,7 @@
debian/frr.conf usr/lib/tmpfiles.d
etc/
tools/etc/frr/frr.conf etc/frr/
+tools/etc/logrotate.d/frr etc/logrotate.d/
tools/frr-reload usr/lib/frr/
usr/bin/mtracebis
usr/bin/vtysh
diff --git a/debian/frr.pam b/debian/frr.pam
index 2b106d43b..737b88953 100644
--- a/debian/frr.pam
+++ b/debian/frr.pam
@@ -1,3 +1,4 @@
# Any user may call vtysh but only those belonging to the group frrvty can
# actually connect to the socket and use the program.
auth sufficient pam_permit.so
+account sufficient pam_rootok.so
diff --git a/doc/developer/cli.rst b/doc/developer/cli.rst
index ff6c4f6e1..d51f06d11 100644
--- a/doc/developer/cli.rst
+++ b/doc/developer/cli.rst
@@ -453,9 +453,7 @@ all DEFPY statements**:
/* GPL header */
#include ...
...
- #ifndef VTYSH_EXTRACT_PL
#include "daemon/filename_clippy.c"
- #endif
DEFPY(...)
DEFPY(...)
diff --git a/doc/developer/conf.py b/doc/developer/conf.py
index 79f823397..495c604ae 100644
--- a/doc/developer/conf.py
+++ b/doc/developer/conf.py
@@ -118,14 +118,6 @@ version = release.split("-")[0]
for key, value in replace_vars.items():
rst_prolog += ".. |{0}| replace:: {1}\n".format(key, value)
-
-# The language for content autogenerated by Sphinx. Refer to documentation
-# for a list of supported languages.
-#
-# This is also used if you do content translation via gettext catalogs.
-# Usually you set "language" from the command line for these cases.
-language = None
-
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
# today = ''
diff --git a/doc/developer/vtysh.rst b/doc/developer/vtysh.rst
index 160676a7b..323ea57c1 100644
--- a/doc/developer/vtysh.rst
+++ b/doc/developer/vtysh.rst
@@ -43,9 +43,14 @@ simplifying the output. This is discussed in :ref:`vtysh-configuration`.
Command Extraction
------------------
-When VTYSH is built, a Perl script named :file:`extract.pl` searches the FRR
-codebase looking for ``DEFUN``'s. It extracts these ``DEFUN``'s, transforms
-them into ``DEFSH``'s and appends them to ``vtysh_cmd.c``. Each ``DEFSH``
+To build ``vtysh``, the :file:`python/xref2vtysh.py` script scans through the
+:file:`frr.xref` file created earlier in the build process. This file contains
+a list of all ``DEFUN`` and ``install_element`` sites in the code, generated
+directly from the binaries (and therefore matching exactly what is really
+available.)
+
+This list is collated and transformed into ``DEFSH`` (and ``install_element``)
+statements, output to ``vtysh_cmd.c``. Each ``DEFSH``
contains the name of the command plus ``_vtysh``, as well as a flag that
indicates which daemons the command was found in. When the command is executed
in VTYSH, this flag is inspected to determine which daemons to send the command
@@ -55,6 +60,12 @@ avoiding spurious errors from daemons that don't have the command defined.
The extraction script contains lots of hardcoded knowledge about what sources
to look at and what flags to use for certain commands.
+.. note::
+
+ The ``vtysh_scan`` Makefile variable and ``#ifndef VTYSH_EXTRACT_PL``
+ checks in source files are no longer used. Remove them when rebasing older
+ changes.
+
.. _vtysh-special-defuns:
Special DEFUNs
@@ -69,7 +80,7 @@ several VTYSH-specific ``DEFUN`` variants that each serve different purposes.
simply forwarded to the daemons indicated in the daemon flag.
``DEFUN_NOSH``
- Used by daemons. Has the same expansion as a ``DEFUN``, but ``extract.pl``
+ Used by daemons. Has the same expansion as a ``DEFUN``, but ``xref2vtysh.py``
will skip these definitions when extracting commands. This is typically used
when VTYSH must take some special action upon receiving the command, and the
programmer therefore needs to write VTYSH's copy of the command manually
diff --git a/doc/manpages/conf.py b/doc/manpages/conf.py
index 186f7932b..73dea094a 100644
--- a/doc/manpages/conf.py
+++ b/doc/manpages/conf.py
@@ -114,14 +114,6 @@ version = release.split("-")[0]
for key, value in replace_vars.items():
rst_prolog += ".. |{0}| replace:: {1}\n".format(key, value)
-
-# The language for content autogenerated by Sphinx. Refer to documentation
-# for a list of supported languages.
-#
-# This is also used if you do content translation via gettext catalogs.
-# Usually you set "language" from the command line for these cases.
-language = None
-
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
# today = ''
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index da3718fce..44349976f 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -148,6 +148,12 @@ bottom until one of the factors can be used.
Prefer higher local preference routes to lower.
+ If ``bgp bestpath aigp`` is enabled, and both paths that are compared have
+ AIGP attribute, BGP uses AIGP tie-breaking unless both of the paths have the
+ AIGP metric attribute. This means that the AIGP attribute is not evaluated
+ during the best path selection process between two paths when one path does
+ not have the AIGP attribute.
+
3. **Local route check**
Prefer local routes (statics, aggregates, redistributed) to received routes.
@@ -401,6 +407,17 @@ Route Selection
paths learned from any of eBGP, iBGP, or confederation neighbors will
be multipath if they are otherwise considered equal cost.
+.. clicmd:: bgp bestpath aigp
+
+ Use the bgp bestpath aigp command to evaluate the AIGP attribute during
+ the best path selection process between two paths that have the AIGP
+ attribute.
+
+ When bgp bestpath aigp is disabled, BGP does not use AIGP tie-breaking
+ rules unless paths have the AIGP attribute.
+
+ Disabled by default.
+
.. clicmd:: maximum-paths (1-128)
Sets the maximum-paths value used for ecmp calculations for this
@@ -1035,7 +1052,7 @@ Long-lived Graceful Restart
Currently, only restarter mode is supported. This capability is advertised only
if graceful restart capability is negotiated.
-.. clicmd:: bgp long-lived-graceful-restart stale-time (1-4294967295)
+.. clicmd:: bgp long-lived-graceful-restart stale-time (1-16777215)
Specifies the maximum time to wait before purging long-lived stale routes for
helper routers.
@@ -1670,6 +1687,23 @@ Configuring Peers
turning on this command will allow BGP to install v4 routes with
v6 nexthops if you do not have v4 configured on interfaces.
+.. clicmd:: neighbor <A.B.C.D|X:X::X:X|WORD> accept-own
+
+ Enable handling of self-originated VPN routes containing ``accept-own`` community.
+
+ This feature allows you to handle self-originated VPN routes, which a BGP speaker
+ receives from a route-reflector. A 'self-originated' route is one that was
+ originally advertised by the speaker itself. As per :rfc:`4271`, a BGP speaker rejects
+ advertisements that originated the speaker itself. However, the BGP ACCEPT_OWN
+ mechanism enables a router to accept the prefixes it has advertised, when reflected
+ from a route-reflector that modifies certain attributes of the prefix.
+
+ A special community called ``accept-own`` is attached to the prefix by the
+ route-reflector, which is a signal to the receiving router to bypass the ORIGINATOR_ID
+ and NEXTHOP/MP_REACH_NLRI check.
+
+ Default: disabled.
+
.. clicmd:: bgp fast-external-failover
This command causes bgp to take down ebgp peers immediately
@@ -1775,21 +1809,19 @@ Configuring Peers
default, the DelayOpenTimer is disabled. The timer interval may be set to a
duration of 1 to 240 seconds.
-.. clicmd:: neighbor PEER extended-optional-parameters
-
- Force the extended optional parameters format for OPEN messages. By default,
- optional parameters length is 255 octets. With more and more BGP capabilities
- implemented on top of BGP, this is needed to extend this value.
-
- This is turned off by default, but it's automatically enabled when this limit
- is hit. You can force this new encoding to be enabled with this command.
-
.. clicmd:: bgp minimum-holdtime (1-65535)
This command allows user to prevent session establishment with BGP peers
with lower holdtime less than configured minimum holdtime.
When this command is not set, minimum holdtime does not work.
+.. clicmd:: bgp tcp-keepalive (1-65535) (1-65535) (1-30)
+
+ This command allows user to configure TCP keepalive with new BGP peers.
+ Each parameter respectively stands for TCP keepalive idle timer (seconds),
+ interval (seconds), and maximum probes. By default, TCP keepalive is
+ disabled.
+
Displaying Information about Peers
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -2897,6 +2929,23 @@ L3VPN SRv6
Specify the SRv6 locator to be used for SRv6 L3VPN. The Locator name must
be set in zebra, but user can set it in any order.
+General configuration
+^^^^^^^^^^^^^^^^^^^^^
+
+Configuration of the SRv6 SID used to advertise a L3VPN for both IPv4 and IPv6
+is accomplished via the following command in the context of a VRF:
+
+.. clicmd:: sid vpn per-vrf export (1..255)|auto
+
+ Enables a SRv6 SID to be attached to a route exported from the current
+ unicast VRF to VPN. A single SID is used for both IPv4 and IPv6 address
+ families. If you want to set a SID for only IPv4 address family or IPv6
+ address family, you need to use the command ``sid vpn export (1..255)|auto``
+ in the context of an address-family. If the value specified is ``auto``,
+ the SID value is automatically assigned from a pool maintained by the Zebra
+ daemon. If Zebra is not running, or if this command is not configured, automatic
+ SID assignment will not complete, which will block corresponding route export.
+
.. _bgp-evpn:
Ethernet Virtual Network - EVPN
@@ -2920,6 +2969,20 @@ sysctl configurations:
For more information, see ``man 7 arp``.
+.. _bgp-evpn-l3-route-targets:
+
+EVPN L3 Route-Targets
+^^^^^^^^^^^^^^^^^^^^^
+
+.. clicmd:: route-target <import|export|both> <RTLIST|auto>
+
+Modify the route-target set for EVPN advertised type-2/type-5 routes.
+RTLIST is a list of any of matching
+``(A.B.C.D:MN|EF:OPQR|GHJK:MN|*:OPQR|*:MN)`` where ``*`` indicates wildcard
+matching for the AS number. It will be set to match any AS number. This is
+useful in datacenter deployments with Downstream VNI. ``auto`` is used to
+retain the autoconfigure that is default behavior for L3 RTs.
+
.. _bgp-evpn-advertise-pip:
EVPN advertise-PIP
@@ -3471,6 +3534,319 @@ When default route is not present in R2'2 BGP table, 10.139.224.0/20 and 192.0.2
Total number of prefixes 3
Router2#
+.. _bgp-optimal-route-reflection:
+
+BGP Optimal Route Reflection
+----------------------------
+BGP Route Reflectors (RRs) are used to improve network scalability by reducing
+or eliminating the need for a full-mesh of IBGP sessions.
+
+When a BGP RR receives multiple paths for the same IP prefix, it typically
+selects a single best path to send for all its clients.
+If the RR has multiple nearly-equal best paths and the tie-break is determined
+by the next-hop cost, the RR advertises the path based on its view of next-hop
+costs, which leads to a non-optimal routing.
+The advertised route may differ from the path that a client would select
+if it had the visibility of the same set of candidate paths and used
+its own view of next-hop costs.
+
+Non-optimal advertisements by the RR can be a problem in hot-potato routing.
+Hot-potato routing aims to hand off traffic to the next AS using the closest
+possible exit point from the local AS.
+In this context, the closest exit point implies minimum IGP cost to
+reach the BGP next-hop.
+
+The BGP Optimal Route Reflection allows the RR to choose and send a different
+best path to a different or a set of RR clients.
+
+A link-state protocol is required. It can be OSPF or IS-IS.
+Current implementation of BGP ORR is based on the IGP cost to the BGP next hop,
+and not based on some configured policy.
+
+RR runs Shortest Path First (SPF) calculation with the selected
+router as the root of the tree and calculates the cost to every other router.
+
+This special SPF calculation with another router as the root, is referred to as
+a Reverse SPF (rSPF). This can only be done if the RR learns all the BGP paths
+from all the BGP border routers.
+
+There could be as many rSPFs run as there are RR clients.
+This will increase the CPU load somewhat on the RR.
+
+Current implementation allows up to three root nodes for the rSPF calculation.
+There is no need to configure each RR client as a root and run rSPF.
+Current implementation allows to configure three, the primary, the secondary,
+and the tertiary root, per set of RR clients, for redundancy purposes.
+For the BGP ORR feature to apply to any RR client, that RR client must be
+configured to be part of an ORR policy group.
+
+The BGP ORR feature is enabled per address family.
+
+The minimal configuration needed:
+
+1. ORR needs to be enabled for specific groups of BGP neighbors.
+2. For each group of BGP neighbors, at least one root needs to be configured.
+ Optionally, a secondary and tertiary root can be configured.
+3. For OSPF, the root routers(RR clients) need additional configuration
+ to make BGP ORR work.
+ i.e. The MPLS TE configuration on the root router needs to have the minimal
+ configuration for MPLS TE enabled so that OSPF advertises the MPLS TE
+ router ID in an opaque-area LSA (type 10).
+ Once the RR has an opaque-area LSA with the MPLS TE router-ID matching the
+ configured root router address, rSPF can run and BGP on the RR can
+ advertise the optimal route.
+
+.. clicmd:: neighbor A.B.C.D optimal-route-reflection NAME
+
+ This command allows the neighbor to be part of the ORR group.
+
+.. clicmd:: optimal-route-reflection orr-1 A.B.C.D [A.B.C.D] [A.B.C.D]
+
+ This command creates an ORR group with a mandatory primary root
+ and optional secondary and/or tertiary roots.
+ When primary is reachable it will be the active root.
+ when primary goes down, secondary followed by tertiary takes over
+ the active root's role.
+ Always rSPF calculation runs active root as the root.
+ Which means the RR advertises the path based on active root's
+ view of next-hop costs.
+
+Sample Configuration
+^^^^^^^^^^^^^^^^^^^^
+
+Sample configuration on Route Reflector
+
+.. code-block:: frr
+
+ !
+ debug ospf 8 orr
+ debug bgp optimal-route-reflection
+ !
+ interface enp0s8
+ ip address 10.10.68.8/24
+ ip ospf 8 area 0
+ exit
+ !
+ interface lo
+ ip address 10.100.1.8/32
+ ip ospf 8 area 0
+ exit
+ !
+ router bgp 1
+ neighbor 10.100.1.1 remote-as 1
+ neighbor 10.100.1.1 update-source lo
+ neighbor 10.100.1.2 remote-as 1
+ neighbor 10.100.1.2 update-source lo
+ neighbor 10.100.1.3 remote-as 1
+ neighbor 10.100.1.3 update-source lo
+ neighbor 10.100.1.4 remote-as 1
+ neighbor 10.100.1.4 update-source lo
+ !
+ address-family ipv4 unicast
+ neighbor 10.100.1.1 route-reflector-client
+ neighbor 10.100.1.1 optimal-route-reflection orr-1
+ neighbor 10.100.1.2 route-reflector-client
+ neighbor 10.100.1.2 optimal-route-reflection orr-1
+ neighbor 10.100.1.3 route-reflector-client
+ neighbor 10.100.1.3 optimal-route-reflection orr-1
+ neighbor 10.100.1.4 route-reflector-client
+ neighbor 10.100.1.4 optimal-route-reflection orr-1
+ optimal-route-reflection orr-1 10.100.1.4 10.100.1.3 10.100.1.1
+ exit-address-family
+ exit
+ !
+ router ospf 8
+ ospf router-id 8.8.8.8
+ area 0 authentication
+ capability opaque
+ exit
+ !
+ end
+
+Sample configuration on RR clients
+
+.. code-block:: frr
+
+ interface enp0s8
+ ip address 10.10.34.4/24
+ ip ospf 4 area 0
+ link-params
+ enable
+ exit-link-params
+ exit
+ !
+ interface enp0s9
+ ip address 10.10.74.4/24
+ ip ospf 4 area 0
+ link-params
+ enable
+ exit-link-params
+ exit
+ !
+ interface lo
+ ip address 10.100.1.4/32
+ ip ospf 4 area 0
+ exit
+ !
+ router bgp 1
+ neighbor 10.100.1.8 remote-as 1
+ neighbor 10.100.1.8 update-source lo
+ !
+ address-family ipv4 unicast
+ neighbor 10.100.1.8 soft-reconfiguration inbound
+ exit-address-family
+ exit
+ !
+ router ospf 4
+ ospf router-id 4.4.4.4
+ area 0 authentication
+ capability opaque
+ mpls-te on
+ mpls-te router-address 10.100.1.4
+ mpls-te inter-as area 0.0.0.0
+ mpls-te export
+ exit
+ !
+ end
+
+Sample Output
+^^^^^^^^^^^^^
+
+When Optimal Route Reflection is not enabled on RR, it sends 10.100.1.1 as the best path to its clients.
+
+.. code-block:: frr
+
+ Router-RR# show ip bgp neighbors 10.100.1.4
+
+ !--- Output suppressed.
+
+ For address family: IPv4 Unicast
+ Update group 2, subgroup 2
+ Packet Queue length 0
+ Route-Reflector Client
+ Community attribute sent to this neighbor(all)
+ 0 accepted prefixes
+
+ !--- Output suppressed.
+
+ Router-RR#
+ Router-RR# show ip bgp
+ BGP table version is 3, local router ID is 10.100.1.8, vrf id 0
+ Default local pref 100, local AS 1
+ Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
+ i internal, r RIB-failure, S Stale, R Removed
+ Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
+ Origin codes: i - IGP, e - EGP, ? - incomplete
+ RPKI validation codes: V valid, I invalid, N Not found
+
+ Network Next Hop Metric LocPrf Weight Path
+ * i203.0.113.0/24 10.100.1.2 0 100 0 i
+ *>i 10.100.1.1 0 100 0 i
+ *=i 10.100.1.3 0 100 0 i
+
+ Displayed 1 routes and 3 total paths
+ Router-RR#
+
+ Router-PE4# show ip bgp
+ BGP table version is 5, local router ID is 10.100.1.4, vrf id 0
+ Default local pref 100, local AS 1
+ Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
+ i internal, r RIB-failure, S Stale, R Removed
+ Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
+ Origin codes: i - IGP, e - EGP, ? - incomplete
+ RPKI validation codes: V valid, I invalid, N Not found
+
+ Network Next Hop Metric LocPrf Weight Path
+ *>i203.0.113.0/24 10.100.1.1 0 100 0 i
+
+ Displayed 1 routes and 1 total paths
+ Router-PE4#
+
+When Optimal Route Reflection is enabled on RR, it sends 10.100.1.3 as the best path to its clients.
+
+.. code-block:: frr
+
+ Router-RR# show ip bgp neighbors 10.100.1.4
+
+ !--- Output suppressed.
+
+ For address family: IPv4 Unicast
+ Update group 1, subgroup 1
+ Packet Queue length 0
+ Route-Reflector Client
+ ORR group (configured) : orr-1
+ Community attribute sent to this neighbor(all)
+ 0 accepted prefixes
+
+ !--- Output suppressed.
+
+ Router-RR#
+ Router-RR# show ip bgp
+ BGP table version is 1, local router ID is 10.100.1.8, vrf id 0
+ Default local pref 100, local AS 1
+ Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
+ i internal, r RIB-failure, S Stale, R Removed
+ Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
+ Origin codes: i - IGP, e - EGP, ? - incomplete
+ RPKI validation codes: V valid, I invalid, N Not found
+
+ Network Next Hop Metric LocPrf Weight Path
+ * i203.0.113.0/24 10.100.1.2 0 100 0 i
+ *>i 10.100.1.3 0 100 0 i
+ * i 10.100.1.1 0 100 0 i
+
+ Displayed 1 routes and 3 total paths
+ Router-RR#
+
+ Router-RR# show ip bgp optimal-route-reflection
+
+ ORR group: orr-1, IPv4 Unicast
+ Configured root: primary: 10.100.1.4(Router-PE4), secondary: 10.100.1.3(Router-PE3), tertiary: 10.100.1.1(Router-PE1)
+ Active Root: 10.100.1.4(Router-PE4)
+
+ RR Clients mapped:
+ 10.100.1.1
+ 10.100.1.2
+ 10.100.1.3
+ 10.100.1.4
+
+ Number of mapping entries: 4
+
+ Prefix Cost
+ 10.10.34.0/24 100
+ 10.10.61.0/24 300
+ 10.10.63.0/24 200
+ 10.10.67.0/24 200
+ 10.10.68.0/24 300
+ 10.10.72.0/24 200
+ 10.10.74.0/24 100
+ 10.100.1.1/32 300
+ 10.100.1.2/32 200
+ 10.100.1.3/32 100
+ 10.100.1.4/32 0
+ 10.100.1.6/32 200
+ 10.100.1.7/32 100
+ 10.100.1.8/32 300
+
+ Number of mapping entries: 14
+
+ Router-RR#
+
+ Router-PE4# show ip bgp
+ BGP table version is 3, local router ID is 10.100.1.4, vrf id 0
+ Default local pref 100, local AS 1
+ Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
+ i internal, r RIB-failure, S Stale, R Removed
+ Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
+ Origin codes: i - IGP, e - EGP, ? - incomplete
+ RPKI validation codes: V valid, I invalid, N Not found
+
+ Network Next Hop Metric LocPrf Weight Path
+ *>i203.0.113.0/24 10.100.1.3 0 100 0 i
+
+ Displayed 1 routes and 1 total paths
+ Router-PE4#
+
.. _bgp-debugging:
Debugging
@@ -3536,6 +3912,10 @@ Debugging
Enable or disable debugging of communications between *bgpd* and *zebra*.
+.. clicmd:: debug bgp optimal-route-reflection
+
+ Enable or disable debugging of BGP Optimal Route Reflection.
+
Dumping Messages and Routing Tables
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -3655,6 +4035,11 @@ The following command is available in ``config`` mode as well as in the
the startup configuration, graceful shutdown will remain in effect
across restarts of *bgpd* and will need to be explicitly disabled.
+.. clicmd:: bgp input-queue-limit (1-4294967295)
+
+ Set the BGP Input Queue limit for all peers when messaging parsing. Increase
+ this only if you have the memory to handle large queues of messages at once.
+
.. _bgp-displaying-bgp-information:
Displaying BGP Information
diff --git a/doc/user/conf.py b/doc/user/conf.py
index 6db58b07c..728f9c936 100644
--- a/doc/user/conf.py
+++ b/doc/user/conf.py
@@ -117,14 +117,6 @@ version = release.split("-")[0]
for key, value in replace_vars.items():
rst_prolog += ".. |{0}| replace:: {1}\n".format(key, value)
-
-# The language for content autogenerated by Sphinx. Refer to documentation
-# for a list of supported languages.
-#
-# This is also used if you do content translation via gettext catalogs.
-# Usually you set "language" from the command line for these cases.
-language = None
-
# There are two options for replacing |today|: either, you set today to some
# non-false value, then it is used:
# today = ''
diff --git a/doc/user/index.rst b/doc/user/index.rst
index 5a018a558..c8ad85c0c 100644
--- a/doc/user/index.rst
+++ b/doc/user/index.rst
@@ -31,6 +31,7 @@ Basics
kernel
snmp
scripting
+ nexthop_groups
.. modules
#########
diff --git a/doc/user/installation.rst b/doc/user/installation.rst
index ba35facf2..8f89c6c4f 100644
--- a/doc/user/installation.rst
+++ b/doc/user/installation.rst
@@ -368,6 +368,13 @@ options from the list below.
Turn on the usage of PCRE Posix libs for regex functionality.
+.. option:: --enable-pcre2posix
+
+ Turn on the usage of PCRE2 Posix libs for regex functionality.
+
+ PCRE2 versions <= 10.31 work a bit differently. We suggest using at least
+ >= 10.36.
+
.. option:: --enable-rpath
Set hardcoded rpaths in the executable [default=yes].
diff --git a/doc/user/isisd.rst b/doc/user/isisd.rst
index 9ccb5ba4b..2b114ad12 100644
--- a/doc/user/isisd.rst
+++ b/doc/user/isisd.rst
@@ -83,6 +83,10 @@ writing, *isisd* does not support multiple ISIS processes.
Set overload bit to avoid any transit traffic.
+.. clicmd:: set-overload-bit on-startup (0-86400)
+
+ Set overload bit on startup for the specified duration, in seconds. Reference: :rfc:`3277`
+
.. clicmd:: purge-originator
Enable or disable :rfc:`6232` purge originator identification.
diff --git a/doc/user/nexthop_groups.rst b/doc/user/nexthop_groups.rst
new file mode 100644
index 000000000..45f64eecb
--- /dev/null
+++ b/doc/user/nexthop_groups.rst
@@ -0,0 +1,29 @@
+.. _nexthop-groups:
+
+Nexthop Groups
+==============
+
+Nexthop groups are a way to encapsulate ECMP information together. It's a
+listing of ECMP nexthops used to forward packets.
+
+.. clicmd:: nexthop-group NAME
+
+ Create a nexthop-group with an associated NAME. This will put you into a
+ sub-mode where you can specify individual nexthops. To exit this mode type
+ exit or end as per normal conventions for leaving a sub-mode.
+
+.. clicmd:: nexthop [A.B.C.D|X:X::X:XX] [interface [onlink]] [nexthop-vrf NAME] [label LABELS]
+
+ Create a v4 or v6 nexthop. All normal rules for creating nexthops that you
+ are used to are allowed here. The syntax was intentionally kept the same as
+ creating nexthops as you would for static routes.
+
+.. clicmd:: resilient buckets (1-256) idle-timer (1-4294967295) unbalanced-timer (1-4294967295)
+
+ Create a resilient Nexthop Group with the specified number of buckets, and
+ associated timers. Instead of using the normal kernel hashing methodology
+ this specifies that X buckets will be created for the nexthop group and
+ when a nexthop is lost the buckets forwarding that particular nexthop
+ will be automatically re-assigned. This cli command must be the first
+ command entered currently. Additionally this command only works with linux 5.19
+ kernels or newer.
diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst
index 26810bd88..181a6b2f3 100644
--- a/doc/user/ospfd.rst
+++ b/doc/user/ospfd.rst
@@ -195,7 +195,7 @@ To start OSPF process you have to specify the OSPF router.
This command supersedes the *timers spf* command in previous FRR
releases.
-.. clicmd:: max-metric router-lsa [on-startup|on-shutdown] (5-86400)
+.. clicmd:: max-metric router-lsa [on-startup (5-86400)|on-shutdown (5-100)]
.. clicmd:: max-metric router-lsa administrative
@@ -831,6 +831,12 @@ Showing Information
Show the OSPF routing table, as determined by the most recent SPF
calculation.
+.. clicmd:: show ip ospf (1-65535) route orr [NAME]
+
+.. clicmd:: show ip ospf [vrf <NAME|all>] route orr [NAME]
+
+ Show the OSPF routing table, calculated from the active root of all ORR groups or specified ORR group.
+
.. clicmd:: show ip ospf graceful-restart helper [detail] [json]
Displays the Grcaeful Restart Helper details including helper
@@ -1060,78 +1066,87 @@ TI-LFA requires a proper Segment Routing configuration.
Debugging OSPF
==============
-.. clicmd:: debug ospf bfd
+.. clicmd:: debug ospf [(1-65535)] bfd
Enable or disable debugging for BFD events. This will show BFD integration
library messages and OSPF BFD integration messages that are mostly state
transitions and validation problems.
-.. clicmd:: debug ospf client-api
+.. clicmd:: debug ospf [(1-65535)] client-api
Show debug information for the OSPF opaque data client API.
-.. clicmd:: debug ospf packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail]
+.. clicmd:: debug ospf [(1-65535)] default-information
+ Show debug information of default information
- Dump Packet for debugging
+.. clicmd:: debug ospf [(1-65535)] packet (hello|dd|ls-request|ls-update|ls-ack|all) (send|recv) [detail]
-.. clicmd:: debug ospf ism
-.. clicmd:: debug ospf ism (status|events|timers)
+ Dump Packet for debugging
+.. clicmd:: debug ospf [(1-65535)] ism [status|events|timers]
- Show debug information of Interface State Machine
-.. clicmd:: debug ospf nsm
+ Show debug information of Interface State Machine
-.. clicmd:: debug ospf nsm (status|events|timers)
+.. clicmd:: debug ospf [(1-65535)] nsm [status|events|timers]
Show debug information of Network State Machine
-.. clicmd:: debug ospf event
+.. clicmd:: debug ospf [(1-65535)] event
Show debug information of OSPF event
-.. clicmd:: debug ospf nssa
+.. clicmd:: debug ospf [(1-65535)] nssa
Show debug information about Not So Stub Area
-.. clicmd:: debug ospf lsa
+.. clicmd:: debug ospf [(1-65535)] ldp-sync
+
+ Show debug information about LDP-Sync
-.. clicmd:: debug ospf lsa (generate|flooding|refresh)
+.. clicmd:: debug ospf [(1-65535)] lsa [aggregate|flooding|generate|install|refresh]
Show debug detail of Link State messages
-.. clicmd:: debug ospf te
+.. clicmd:: debug ospf [(1-65535)] sr
+
+ Show debug information about Segment Routing
+
+.. clicmd:: debug ospf [(1-65535)] te
Show debug information about Traffic Engineering LSA
-.. clicmd:: debug ospf zebra
+.. clicmd:: debug ospf [(1-65535)] ti-lfa
+
+ Show debug information about SR TI-LFA
-.. clicmd:: debug ospf zebra (interface|redistribute)
+.. clicmd:: debug ospf [(1-65535)] zebra [interface|redistribute]
Show debug information of ZEBRA API
-.. clicmd:: debug ospf graceful-restart helper
+.. clicmd:: debug ospf [(1-65535)] graceful-restart
Enable/disable debug information for OSPF Graceful Restart Helper
.. clicmd:: show debugging ospf
-.. clicmd:: debug ospf lsa aggregate
- Debug commnd to enable/disable external route summarisation specific debugs.
+.. clicmd:: debug ospf orr
+
+ Enable or disable debugging of BGP Optimal Route Reflection.
Sample Configuration
diff --git a/doc/user/pathd.rst b/doc/user/pathd.rst
index f0b76f10b..ec107fbe4 100644
--- a/doc/user/pathd.rst
+++ b/doc/user/pathd.rst
@@ -175,7 +175,7 @@ controller and obtain those by means of the PCEP protocol.
.. image:: images/pathd_initiated_multi.png
Starting
-=============
+========
Default configuration file for *pathd* is :file:`pathd.conf`. The typical
location of :file:`pathd.conf` is |INSTALL_PREFIX_ETC|/pathd.conf.
@@ -480,6 +480,12 @@ Configuration Commands
Specify a peer and its precedence in a PCC definition.
+Debugging
+---------
+
+.. clicmd:: debug pathd policy
+
+ Enable or disable Pathd policy information.
Introspection Commands
----------------------
diff --git a/doc/user/pbr.rst b/doc/user/pbr.rst
index 29567bb70..0cdb206dd 100644
--- a/doc/user/pbr.rst
+++ b/doc/user/pbr.rst
@@ -32,26 +32,8 @@ Nexthop Groups
Nexthop groups are a way to encapsulate ECMP information together. It's a
listing of ECMP nexthops used to forward packets for when a pbr-map is matched.
-
-.. clicmd:: nexthop-group NAME
-
- Create a nexthop-group with an associated NAME. This will put you into a
- sub-mode where you can specify individual nexthops. To exit this mode type
- exit or end as per normal conventions for leaving a sub-mode.
-
-.. clicmd:: nexthop [A.B.C.D|X:X::X:XX] [interface [onlink]] [nexthop-vrf NAME] [label LABELS]
-
- Create a v4 or v6 nexthop. All normal rules for creating nexthops that you
- are used to are allowed here. The syntax was intentionally kept the same as
- creating nexthops as you would for static routes.
-
-.. clicmd:: pbr table range (10000-4294966272) (10000-4294966272)
-
- Set or unset the range used to assign numeric table ID's to new
- nexthop-group tables. Existing tables will not be modified to fit in this
- range, so it is recommended to configure this before adding nexthop groups.
-
- .. seealso:: :ref:`pbr-details`
+For detailed instructions on how to specify a nexthop group on the CLI, see
+the nexthop-groups section.
Showing Nexthop Group Information
---------------------------------
@@ -301,6 +283,15 @@ causes the policy to be installed into the kernel.
| valid | Is the map well-formed? | Boolean |
+--------+----------------------------+---------+
+.. clicmd:: pbr table range (10000-4294966272) (10000-4294966272)
+
+ Set or unset the range used to assign numeric table ID's to new
+ nexthop-group tables. Existing tables will not be modified to fit in this
+ range, so it is recommended to configure this before adding nexthop groups.
+
+ .. seealso:: :ref:`pbr-details`
+
+
.. _pbr-debugs:
PBR Debugs
@@ -310,10 +301,6 @@ PBR Debugs
Debug pbr in pbrd daemon. You specify what types of debugs to turn on.
-.. clicmd:: debug zebra pbr
-
- Debug pbr in zebra daemon.
-
.. _pbr-details:
PBR Details
diff --git a/doc/user/pim.rst b/doc/user/pim.rst
index 44ade916a..5d849c7b8 100644
--- a/doc/user/pim.rst
+++ b/doc/user/pim.rst
@@ -578,7 +578,7 @@ cause great confusion.
.. clicmd:: show ip pim bsm-database
- Display all fragments ofstored bootstrap message in user readable format.
+ Display all fragments of stored bootstrap message in user readable format.
.. clicmd:: mtrace A.B.C.D [A.B.C.D]
diff --git a/doc/user/pimv6.rst b/doc/user/pimv6.rst
index b242f4fe1..7fd285600 100644
--- a/doc/user/pimv6.rst
+++ b/doc/user/pimv6.rst
@@ -162,6 +162,18 @@ is in a vrf, enter the interface command with the vrf keyword at the end.
Disable sending and receiving pim control packets on the interface.
+.. clicmd:: ipv6 pim bsm
+
+ Tell pim that we would like to use this interface to process bootstrap
+ messages. This is enabled by default. 'no' form of this command is used to
+ restrict bsm messages on this interface.
+
+.. clicmd:: ipv6 pim unicast-bsm
+
+ Tell pim that we would like to allow interface to process unicast bootstrap
+ messages. This is enabled by default. 'no' form of this command is used to
+ restrict processing of unicast bsm messages on this interface.
+
.. clicmd:: ipv6 mld
Tell pim to receive MLD reports and Query on this interface. The default
@@ -373,6 +385,18 @@ General multicast routing state
Display total number of S,G mroutes and number of S,G mroutes
installed into the kernel for all vrfs.
+.. clicmd:: show ipv6 pim bsr
+
+ Display current bsr, its uptime and last received bsm age.
+
+.. clicmd:: show ipv6 pim bsrp-info
+
+ Display group-to-rp mappings received from E-BSR.
+
+.. clicmd:: show ipv6 pim bsm-database
+
+ Display all fragments of stored bootstrap message in user readable format.
+
PIMv6 Clear Commands
====================
@@ -472,3 +496,7 @@ the config was written out.
.. clicmd:: debug mld trace [detail]
This traces mld code and how it is running.
+
+.. clicmd:: debug pimv6 bsm
+
+ This turns on debugging for BSR message processing.
diff --git a/doc/user/routemap.rst b/doc/user/routemap.rst
index 5e222576c..c205122b0 100644
--- a/doc/user/routemap.rst
+++ b/doc/user/routemap.rst
@@ -310,6 +310,11 @@ Route Map Set Command
trip time or `+rtt`/`-rtt` to add/subtract the round trip time to/from the
MED.
+.. clicmd:: set aigp-metric <igp-metric|(1-4294967295)>
+
+ Set the BGP attribute AIGP to a specific value. If ``igp-metric`` is specified,
+ then the value is taken from the IGP protocol, otherwise an arbitrary value.
+
.. clicmd:: set as-path prepend AS_PATH
Set the BGP AS path to prepend.
diff --git a/doc/user/sharp.rst b/doc/user/sharp.rst
index 8d201a3c0..3e73a599e 100644
--- a/doc/user/sharp.rst
+++ b/doc/user/sharp.rst
@@ -187,7 +187,7 @@ keyword. At present, no sharp commands will be preserved in the config.
There are many End Functions defined in SRv6, which have been standardized
in RFC 8986. The current implementation supports End, End.X, End.T, End.DX4,
- and End.DT6, which can be configured as follows.
+ End.DT6 and End.DT46, which can be configured as follows.
::
@@ -196,6 +196,7 @@ keyword. At present, no sharp commands will be preserved in the config.
router# sharp install seg6local-routes 1::3 nexthop-seg6local dum0 End_T 10 1
router# sharp install seg6local-routes 1::4 nexthop-seg6local dum0 End_DX4 10.0.0.1 1
router# sharp install seg6local-routes 1::5 nexthop-seg6local dum0 End_DT6 10 1
+ router# sharp install seg6local-routes 1::6 nexthop-seg6local dum0 End_DT46 10 1
router# show ipv6 route
D>* 1::1/128 [150/0] is directly connected, dum0, seg6local End USP, weight 1, 00:00:05
@@ -203,6 +204,7 @@ keyword. At present, no sharp commands will be preserved in the config.
D>* 1::3/128 [150/0] is directly connected, dum0, seg6local End.T table 10, weight 1, 00:00:05
D>* 1::4/128 [150/0] is directly connected, dum0, seg6local End.DX4 nh4 10.0.0.1, weight 1, 00:00:05
D>* 1::5/128 [150/0] is directly connected, dum0, seg6local End.DT6 table 10, weight 1, 00:00:05
+ D>* 1::6/128 [150/0] is directly connected, dum0, seg6local End.DT46 table 10, weight 1, 00:00:05
bash# ip -6 route
1::1 encap seg6local action End dev dum0 proto 194 metric 20 pref medium
@@ -210,6 +212,7 @@ keyword. At present, no sharp commands will be preserved in the config.
1::3 encap seg6local action End.T table 10 dev dum0 proto 194 metric 20 pref medium
1::4 encap seg6local action End.DX4 nh4 10.0.0.1 dev dum0 proto 194 metric 20 pref medium
1::5 encap seg6local action End.DT6 table 10 dev dum0 proto 194 metric 20 pref medium
+ 1::6 encap seg6local action End.DT46 table 10 dev dum0 proto 194 metric 20 pref medium
.. clicmd:: show sharp segment-routing srv6
diff --git a/doc/user/subdir.am b/doc/user/subdir.am
index 14ace2c85..825938b31 100644
--- a/doc/user/subdir.am
+++ b/doc/user/subdir.am
@@ -22,6 +22,7 @@ user_RSTFILES = \
doc/user/ipv6.rst \
doc/user/isisd.rst \
doc/user/kernel.rst \
+ doc/user/nexthop_groups.rst \
doc/user/nhrpd.rst \
doc/user/ospf6d.rst \
doc/user/ospfd.rst \
diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst
index 05990e252..db43266d6 100644
--- a/doc/user/zebra.rst
+++ b/doc/user/zebra.rst
@@ -745,7 +745,7 @@ and this section also helps that case.
Create a new locator. If the name of an existing locator is specified,
move to specified locator's configuration node to change the settings it.
-.. clicmd:: prefix X:X::X:X/M [func-bits 32]
+.. clicmd:: prefix X:X::X:X/M [func-bits (0-64)] [block-len 40] [node-len 24]
Set the ipv6 prefix block of the locator. SRv6 locator is defined by
RFC8986. The actual routing protocol specifies the locator and allocates a
@@ -764,10 +764,33 @@ and this section also helps that case.
configure the locator's prefix as ``2001:db8:1:1::/64``, then default SID
will be ``2001:db8:1:1:1::``)
+ This command takes three optional parameters: ``func-bits``, ``block-len``
+ and ``node-len``. These parameters allow users to set the format for the SIDs
+ allocated from the SRv6 Locator. SID Format is defined in RFC 8986.
+
+ According to RFC 8986, an SRv6 SID consists of BLOCK:NODE:FUNCTION:ARGUMENT,
+ where BLOCK is the SRv6 SID block (i.e., the IPv6 prefix allocated for SRv6
+ SIDs by the operator), NODE is the identifier of the parent node instantiating
+ the SID, FUNCTION identifies the local behavior associated to the SID and
+ ARGUMENT encodes additional information used to process the behavior.
+ BLOCK and NODE make up the SRv6 Locator.
+
The function bits range is 16bits by default. If operator want to change
function bits range, they can configure with ``func-bits``
option.
+ The ``block-len`` and ``node-len`` parameters allow the user to configure the
+ length of the SRv6 SID block and SRv6 SID node, respectively. Both the lengths
+ are expressed in bits.
+
+ ``block-len``, ``node-len`` and ``func-bits`` may be any value as long as
+ ``block-len+node-len = locator-len`` and ``block-len+node-len+func-bits <= 128``.
+
+ When both ``block-len`` and ``node-len`` are omitted, the following default
+ values are used: ``block-len = 24``, ``node-len = prefix-len-24``.
+
+ If only one parameter is omitted, the other parameter is derived from the first.
+
::
router# configure terminal
@@ -787,6 +810,36 @@ and this section also helps that case.
!
...
+.. clicmd:: behavior usid
+
+ Specify the SRv6 locator as a Micro-segment (uSID) locator. When a locator is
+ specified as a uSID locator, all the SRv6 SIDs allocated from the locator by the routing
+ protocols are bound to the SRv6 uSID behaviors. For example, if you configure BGP to use
+ a locator specified as a uSID locator, BGP instantiates and advertises SRv6 uSID behaviors
+ (e.g., ``uDT4`` / ``uDT6`` / ``uDT46``) instead of classic SRv6 behaviors
+ (e.g., ``End.DT4`` / ``End.DT6`` / ``End.DT46``).
+
+::
+
+ router# configure terminal
+ router(config)# segment-routinig
+ router(config-sr)# srv6
+ router(config-srv6)# locators
+ router(config-srv6-locators)# locator loc1
+ router(config-srv6-locator)# prefix fc00:0:1::/48 block-len 32 node-len 16 func-bits 16
+ router(config-srv6-locator)# behavior usid
+
+ router(config-srv6-locator)# show run
+ ...
+ segment-routing
+ srv6
+ locators
+ locator loc1
+ prefix fc00:0:1::/48
+ behavior usid
+ !
+ ...
+
.. _multicast-rib-commands:
Multicast RIB Commands
@@ -1024,7 +1077,7 @@ FPM Commands
.. clicmd:: fpm connection ip A.B.C.D port (1-65535)
Configure ``zebra`` to connect to a different FPM server than the default of
- ``127.0.0.1:2060``
+ ``127.0.0.1:2620``
.. clicmd:: show zebra fpm stats
diff --git a/docker/alpine/Dockerfile b/docker/alpine/Dockerfile
index b9278dbb8..238a7fc40 100644
--- a/docker/alpine/Dockerfile
+++ b/docker/alpine/Dockerfile
@@ -1,7 +1,7 @@
# syntax=docker/dockerfile:1
# Create a basic stage set up to build APKs
-FROM alpine:3.15 as alpine-builder
+FROM alpine:3.16 as alpine-builder
RUN apk add \
--update-cache \
abuild \
@@ -13,7 +13,7 @@ RUN apk add \
RUN adduser -D -G abuild builder && su builder -c 'abuild-keygen -a -n'
# This stage builds a dist tarball from the source
-FROM alpine:3.15 as source-builder
+FROM alpine:3.16 as source-builder
RUN mkdir -p /src/alpine
COPY alpine/APKBUILD.in /src/alpine
@@ -48,7 +48,7 @@ RUN cd /dist \
&& abuild -r -P /pkgs/apk
# This stage installs frr from the apk
-FROM alpine:3.15
+FROM alpine:3.16
RUN mkdir -p /pkgs/apk
COPY --from=alpine-apk-builder /pkgs/apk/ /pkgs/apk/
RUN apk add \
diff --git a/eigrpd/eigrp_cli.c b/eigrpd/eigrp_cli.c
index 744f5f9c7..2afd9d5ea 100644
--- a/eigrpd/eigrp_cli.c
+++ b/eigrpd/eigrp_cli.c
@@ -31,9 +31,7 @@
#include "eigrp_zebra.h"
#include "eigrp_cli.h"
-#ifndef VTYSH_EXTRACT_PL
#include "eigrpd/eigrp_cli_clippy.c"
-#endif /* VTYSH_EXTRACT_PL */
/*
* XPath: /frr-eigrpd:eigrpd/instance
diff --git a/eigrpd/eigrp_dump.c b/eigrpd/eigrp_dump.c
index e1ad51a9d..b0d34f55e 100644
--- a/eigrpd/eigrp_dump.c
+++ b/eigrpd/eigrp_dump.c
@@ -322,6 +322,7 @@ DEFUN_NOSH (show_debugging_eigrp,
}
}
+ cmd_show_lib_debugs(vty);
return CMD_SUCCESS;
}
diff --git a/eigrpd/eigrp_vty.c b/eigrpd/eigrp_vty.c
index 3d61294b2..137f9b028 100644
--- a/eigrpd/eigrp_vty.c
+++ b/eigrpd/eigrp_vty.c
@@ -55,9 +55,7 @@
#include "eigrpd/eigrp_dump.h"
#include "eigrpd/eigrp_const.h"
-#ifndef VTYSH_EXTRACT_PL
#include "eigrpd/eigrp_vty_clippy.c"
-#endif
static void eigrp_vty_display_prefix_entry(struct vty *vty, struct eigrp *eigrp,
struct eigrp_prefix_descriptor *pe,
diff --git a/eigrpd/subdir.am b/eigrpd/subdir.am
index 3b647e060..e417132b5 100644
--- a/eigrpd/subdir.am
+++ b/eigrpd/subdir.am
@@ -4,12 +4,6 @@
if EIGRPD
sbin_PROGRAMS += eigrpd/eigrpd
-vtysh_scan += \
- eigrpd/eigrp_cli.c \
- eigrpd/eigrp_dump.c \
- eigrpd/eigrp_vty.c \
- # end
-# eigrpd/eigrp_routemap.c
vtysh_daemons += eigrpd
man8 += $(MANBUILD)/frr-eigrpd.8
endif
diff --git a/grpc/subdir.am b/grpc/subdir.am
index cbebd7232..06b37f91d 100644
--- a/grpc/subdir.am
+++ b/grpc/subdir.am
@@ -28,6 +28,13 @@ am__v_PROTOC_1 =
SUFFIXES += .pb.h .pb.cc .grpc.pb.cc
+grpc/frr-northbound.grpc.pb.h: grpc/frr-northbound.grpc.pb.cc
+ @test -f $@ || rm -f $< || true
+ @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) $<
+grpc/frr-northbound.pb.h: grpc/frr-northbound.pb.cc
+ @test -f $@ || rm -f $< || true
+ @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) $<
+
.proto.pb.cc:
$(AM_V_PROTOC)$(PROTOC) -I$(top_srcdir) --cpp_out=$(top_builddir) $^
.proto.grpc.pb.cc:
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index 71ad7bf69..d03ed4d16 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -185,9 +185,6 @@ enum {
RTM_GETNEXTHOPBUCKET,
#define RTM_GETNEXTHOPBUCKET RTM_GETNEXTHOPBUCKET
- RTM_SETHWFLAGS = 119,
-#define RTM_SETHWFLAGS RTM_SETHWFLAGS
-
RTM_NEWTUNNEL = 120,
#define RTM_NEWTUNNEL RTM_NEWTUNNEL
RTM_DELTUNNEL,
diff --git a/include/linux/seg6_local.h b/include/linux/seg6_local.h
index bb5c8ddfc..ab724498a 100644
--- a/include/linux/seg6_local.h
+++ b/include/linux/seg6_local.h
@@ -27,6 +27,7 @@ enum {
SEG6_LOCAL_OIF,
SEG6_LOCAL_BPF,
SEG6_LOCAL_VRFTABLE,
+ SEG6_LOCAL_COUNTERS,
__SEG6_LOCAL_MAX,
};
#define SEG6_LOCAL_MAX (__SEG6_LOCAL_MAX - 1)
@@ -63,6 +64,8 @@ enum {
SEG6_LOCAL_ACTION_END_AM = 14,
/* custom BPF action */
SEG6_LOCAL_ACTION_END_BPF = 15,
+ /* decap and lookup of DA in v4 or v6 table */
+ SEG6_LOCAL_ACTION_END_DT46 = 16,
__SEG6_LOCAL_ACTION_MAX,
};
@@ -78,4 +81,33 @@ enum {
#define SEG6_LOCAL_BPF_PROG_MAX (__SEG6_LOCAL_BPF_PROG_MAX - 1)
+/* SRv6 Behavior counters are encoded as netlink attributes guaranteeing the
+ * correct alignment.
+ * Each counter is identified by a different attribute type (i.e.
+ * SEG6_LOCAL_CNT_PACKETS).
+ *
+ * - SEG6_LOCAL_CNT_PACKETS: identifies a counter that counts the number of
+ * packets that have been CORRECTLY processed by an SRv6 Behavior instance
+ * (i.e., packets that generate errors or are dropped are NOT counted).
+ *
+ * - SEG6_LOCAL_CNT_BYTES: identifies a counter that counts the total amount
+ * of traffic in bytes of all packets that have been CORRECTLY processed by
+ * an SRv6 Behavior instance (i.e., packets that generate errors or are
+ * dropped are NOT counted).
+ *
+ * - SEG6_LOCAL_CNT_ERRORS: identifies a counter that counts the number of
+ * packets that have NOT been properly processed by an SRv6 Behavior instance
+ * (i.e., packets that generate errors or are dropped).
+ */
+enum {
+ SEG6_LOCAL_CNT_UNSPEC,
+ SEG6_LOCAL_CNT_PAD, /* pad for 64 bits values */
+ SEG6_LOCAL_CNT_PACKETS,
+ SEG6_LOCAL_CNT_BYTES,
+ SEG6_LOCAL_CNT_ERRORS,
+ __SEG6_LOCAL_CNT_MAX,
+};
+
+#define SEG6_LOCAL_CNT_MAX (__SEG6_LOCAL_CNT_MAX - 1)
+
#endif
diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c
index 00763135e..0957c897e 100644
--- a/isisd/isis_adjacency.c
+++ b/isisd/isis_adjacency.c
@@ -212,6 +212,36 @@ static const char *adj_level2string(int level)
return NULL; /* not reached */
}
+static void isis_adj_route_switchover(struct isis_adjacency *adj)
+{
+ union g_addr ip = {};
+ ifindex_t ifindex;
+ unsigned int i;
+
+ if (!adj->circuit || !adj->circuit->interface)
+ return;
+
+ ifindex = adj->circuit->interface->ifindex;
+
+ for (i = 0; i < adj->ipv4_address_count; i++) {
+ ip.ipv4 = adj->ipv4_addresses[i];
+ isis_circuit_switchover_routes(adj->circuit, AF_INET, &ip,
+ ifindex);
+ }
+
+ for (i = 0; i < adj->ll_ipv6_count; i++) {
+ ip.ipv6 = adj->ll_ipv6_addrs[i];
+ isis_circuit_switchover_routes(adj->circuit, AF_INET6, &ip,
+ ifindex);
+ }
+
+ for (i = 0; i < adj->global_ipv6_count; i++) {
+ ip.ipv6 = adj->global_ipv6_addrs[i];
+ isis_circuit_switchover_routes(adj->circuit, AF_INET6, &ip,
+ ifindex);
+ }
+}
+
void isis_adj_process_threeway(struct isis_adjacency *adj,
struct isis_threeway_adj *tw_adj,
enum isis_adj_usage adj_usage)
@@ -298,6 +328,16 @@ void isis_adj_state_change(struct isis_adjacency **padj,
if (new_state == old_state)
return;
+ if (old_state == ISIS_ADJ_UP &&
+ !CHECK_FLAG(adj->circuit->flags, ISIS_CIRCUIT_IF_DOWN_FROM_Z)) {
+ if (IS_DEBUG_EVENTS)
+ zlog_debug(
+ "ISIS-Adj (%s): Starting fast-reroute on state change %d->%d: %s",
+ circuit->area->area_tag, old_state, new_state,
+ reason ? reason : "unspecified");
+ isis_adj_route_switchover(adj);
+ }
+
adj->adj_state = new_state;
send_hello_sched(circuit, adj->level, TRIGGERED_IIH_DELAY);
diff --git a/isisd/isis_adjacency.h b/isisd/isis_adjacency.h
index 7467a619c..49adc89ae 100644
--- a/isisd/isis_adjacency.h
+++ b/isisd/isis_adjacency.h
@@ -151,5 +151,4 @@ void isis_adj_build_up_list(struct list *adjdb, struct list *list);
int isis_adj_usage2levels(enum isis_adj_usage usage);
void isis_bfd_startup_timer(struct thread *thread);
const char *isis_adj_name(const struct isis_adjacency *adj);
-
#endif /* ISIS_ADJACENCY_H */
diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c
index dcc4ed6e4..fa0f2c998 100644
--- a/isisd/isis_circuit.c
+++ b/isisd/isis_circuit.c
@@ -598,6 +598,32 @@ size_t isis_circuit_pdu_size(struct isis_circuit *circuit)
return ISO_MTU(circuit);
}
+static bool isis_circuit_lfa_enabled(struct isis_circuit *circuit, int level)
+{
+ return (circuit->lfa_protection[level - 1] ||
+ circuit->rlfa_protection[level - 1] ||
+ circuit->tilfa_protection[level - 1]);
+}
+
+void isis_circuit_switchover_routes(struct isis_circuit *circuit, int family,
+ union g_addr *nexthop_ip, ifindex_t ifindex)
+{
+ char is_type;
+
+ if (!circuit->area)
+ return;
+
+ is_type = circuit->area->is_type;
+ if ((is_type == IS_LEVEL_1 || is_type == IS_LEVEL_1_AND_2) &&
+ isis_circuit_lfa_enabled(circuit, IS_LEVEL_1))
+ isis_area_switchover_routes(circuit->area, family, nexthop_ip,
+ ifindex, IS_LEVEL_1);
+ if ((is_type == IS_LEVEL_2 || is_type == IS_LEVEL_1_AND_2) &&
+ isis_circuit_lfa_enabled(circuit, IS_LEVEL_2))
+ isis_area_switchover_routes(circuit->area, family, nexthop_ip,
+ ifindex, IS_LEVEL_2);
+}
+
void isis_circuit_stream(struct isis_circuit *circuit, struct stream **stream)
{
size_t stream_size = isis_circuit_pdu_size(circuit);
@@ -1602,17 +1628,26 @@ static int isis_ifp_up(struct interface *ifp)
{
struct isis_circuit *circuit = ifp->info;
- if (circuit)
+ if (circuit) {
+ UNSET_FLAG(circuit->flags, ISIS_CIRCUIT_IF_DOWN_FROM_Z);
isis_csm_state_change(IF_UP_FROM_Z, circuit, ifp);
+ }
return 0;
}
static int isis_ifp_down(struct interface *ifp)
{
+ afi_t afi;
struct isis_circuit *circuit = ifp->info;
- if (circuit) {
+ if (circuit &&
+ !CHECK_FLAG(circuit->flags, ISIS_CIRCUIT_IF_DOWN_FROM_Z)) {
+ SET_FLAG(circuit->flags, ISIS_CIRCUIT_IF_DOWN_FROM_Z);
+ for (afi = AFI_IP; afi <= AFI_IP6; afi++)
+ isis_circuit_switchover_routes(
+ circuit, afi == AFI_IP ? AF_INET : AF_INET6,
+ NULL, ifp->ifindex);
isis_csm_state_change(IF_DOWN_FROM_Z, circuit, ifp);
SET_FLAG(circuit->flags, ISIS_CIRCUIT_FLAPPED_AFTER_SPF);
diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h
index 5ff0390c2..b3ad3f7ff 100644
--- a/isisd/isis_circuit.h
+++ b/isisd/isis_circuit.h
@@ -28,6 +28,7 @@
#include "qobj.h"
#include "prefix.h"
#include "ferr.h"
+#include "nexthop.h"
#include "isis_constants.h"
#include "isis_common.h"
@@ -141,6 +142,7 @@ struct isis_circuit {
struct list *ipv6_non_link; /* our non-link local IPv6 addresses */
uint16_t upadjcount[ISIS_LEVELS];
#define ISIS_CIRCUIT_FLAPPED_AFTER_SPF 0x01
+#define ISIS_CIRCUIT_IF_DOWN_FROM_Z 0x02
uint8_t flags;
bool disable_threeway_adj;
struct {
@@ -209,6 +211,9 @@ void isis_circuit_print_vty(struct isis_circuit *circuit, struct vty *vty,
void isis_circuit_print_json(struct isis_circuit *circuit,
struct json_object *json, char detail);
size_t isis_circuit_pdu_size(struct isis_circuit *circuit);
+void isis_circuit_switchover_routes(struct isis_circuit *circuit, int family,
+ union g_addr *nexthop_ip,
+ ifindex_t ifindex);
void isis_circuit_stream(struct isis_circuit *circuit, struct stream **stream);
void isis_circuit_af_set(struct isis_circuit *circuit, bool ip_router,
diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c
index a673cb8c1..3650984f1 100644
--- a/isisd/isis_cli.c
+++ b/isisd/isis_cli.c
@@ -37,9 +37,7 @@
#include "isisd/isis_circuit.h"
#include "isisd/isis_csm.h"
-#ifndef VTYSH_EXTRACT_PL
#include "isisd/isis_cli_clippy.c"
-#endif
#ifndef FABRICD
@@ -404,7 +402,7 @@ DEFPY_YANG(set_overload_bit, set_overload_bit_cmd, "[no] set-overload-bit",
"Reset overload bit to accept transit traffic\n"
"Set overload bit to avoid any transit traffic\n")
{
- nb_cli_enqueue_change(vty, "./overload", NB_OP_MODIFY,
+ nb_cli_enqueue_change(vty, "./overload/enabled", NB_OP_MODIFY,
no ? "false" : "true");
return nb_cli_apply_changes(vty, NULL);
@@ -419,6 +417,42 @@ void cli_show_isis_overload(struct vty *vty, const struct lyd_node *dnode,
}
/*
+ * XPath: /frr-isisd:isis/instance/overload/on-startup
+ */
+DEFPY_YANG(set_overload_bit_on_startup, set_overload_bit_on_startup_cmd,
+ "set-overload-bit on-startup (0-86400)$val",
+ "Set overload bit to avoid any transit traffic\n"
+ "Set overload bit on startup\n"
+ "Set overload time in seconds\n")
+{
+ nb_cli_enqueue_change(vty, "./overload/on-startup", NB_OP_MODIFY,
+ val_str);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFPY_YANG(no_set_overload_bit_on_startup, no_set_overload_bit_on_startup_cmd,
+ "no set-overload-bit on-startup [(0-86400)$val]",
+ NO_STR
+ "Reset overload bit to accept transit traffic\n"
+ "Set overload bit on startup\n"
+ "Set overload time in seconds\n")
+{
+ nb_cli_enqueue_change(vty, "./overload/on-startup", NB_OP_DESTROY,
+ NULL);
+
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+void cli_show_isis_overload_on_startup(struct vty *vty,
+ const struct lyd_node *dnode,
+ bool show_defaults)
+{
+ vty_out(vty, " set-overload-bit on-startup %s\n",
+ yang_dnode_get_string(dnode, NULL));
+}
+
+/*
* XPath: /frr-isisd:isis/instance/attach-send
*/
DEFPY_YANG(attached_bit_send, attached_bit_send_cmd, "[no] attached-bit send",
@@ -3107,6 +3141,9 @@ void isis_cli_init(void)
install_element(ISIS_NODE, &dynamic_hostname_cmd);
install_element(ISIS_NODE, &set_overload_bit_cmd);
+ install_element(ISIS_NODE, &set_overload_bit_on_startup_cmd);
+ install_element(ISIS_NODE, &no_set_overload_bit_on_startup_cmd);
+
install_element(ISIS_NODE, &attached_bit_send_cmd);
install_element(ISIS_NODE, &attached_bit_receive_ignore_cmd);
diff --git a/isisd/isis_lfa.c b/isisd/isis_lfa.c
index c4fadcba0..2ec6dafd3 100644
--- a/isisd/isis_lfa.c
+++ b/isisd/isis_lfa.c
@@ -1836,7 +1836,7 @@ static bool clfa_loop_free_check(struct isis_spftree *spftree,
struct isis_vertex *vertex_S_D,
struct isis_spf_adj *sadj_primary,
struct isis_spf_adj *sadj_N,
- uint32_t *lfa_metric)
+ uint32_t *path_metric)
{
struct isis_spf_node *node_N;
uint32_t dist_N_D;
@@ -1882,7 +1882,7 @@ static bool clfa_loop_free_check(struct isis_spftree *spftree,
dist_N_S, dist_S_D);
if (dist_N_D < (dist_N_S + dist_S_D)) {
- *lfa_metric = sadj_N->metric + dist_N_D;
+ *path_metric = sadj_N->metric + dist_N_D;
return true;
}
@@ -2082,7 +2082,7 @@ void isis_lfa_compute(struct isis_area *area, struct isis_circuit *circuit,
struct isis_spftree *spftree,
struct lfa_protected_resource *resource)
{
- struct isis_vertex *vertex;
+ struct isis_vertex *vertex, *parent_vertex;
struct listnode *vnode, *snode;
int level = spftree->level;
@@ -2099,7 +2099,7 @@ void isis_lfa_compute(struct isis_area *area, struct isis_circuit *circuit,
struct isis_vertex_adj *vadj_primary;
struct isis_spf_adj *sadj_primary;
bool allow_ecmp;
- uint32_t best_metric = UINT32_MAX;
+ uint32_t prefix_metric, best_metric = UINT32_MAX;
char buf[VID2STR_BUFFER];
if (!VTYPE_IP(vertex->type))
@@ -2133,6 +2133,9 @@ void isis_lfa_compute(struct isis_area *area, struct isis_circuit *circuit,
vadj_primary = listnode_head(vertex->Adj_N);
sadj_primary = vadj_primary->sadj;
+ parent_vertex = listnode_head(vertex->parents);
+ prefix_metric = vertex->d_N - parent_vertex->d_N;
+
/*
* Loop over list of SPF adjacencies and compute a list of
* preliminary LFAs.
@@ -2140,7 +2143,7 @@ void isis_lfa_compute(struct isis_area *area, struct isis_circuit *circuit,
lfa_list = list_new();
lfa_list->del = isis_vertex_adj_free;
for (ALL_LIST_ELEMENTS_RO(spftree->sadj_list, snode, sadj_N)) {
- uint32_t lfa_metric;
+ uint32_t lfa_metric, path_metric;
struct isis_vertex_adj *lfa;
struct isis_prefix_sid *psid = NULL;
bool last_hop = false;
@@ -2190,7 +2193,7 @@ void isis_lfa_compute(struct isis_area *area, struct isis_circuit *circuit,
/* Check loop-free criterion. */
if (!clfa_loop_free_check(spftree, vertex, sadj_primary,
- sadj_N, &lfa_metric)) {
+ sadj_N, &path_metric)) {
if (IS_DEBUG_LFA)
zlog_debug(
"ISIS-LFA: LFA condition not met for %s",
@@ -2198,6 +2201,7 @@ void isis_lfa_compute(struct isis_area *area, struct isis_circuit *circuit,
continue;
}
+ lfa_metric = path_metric + prefix_metric;
if (lfa_metric < best_metric)
best_metric = lfa_metric;
@@ -2208,7 +2212,7 @@ void isis_lfa_compute(struct isis_area *area, struct isis_circuit *circuit,
if (vertex->N.ip.sr.present) {
psid = &vertex->N.ip.sr.sid;
- if (lfa_metric == sadj_N->metric)
+ if (path_metric == sadj_N->metric)
last_hop = true;
}
lfa = isis_vertex_adj_add(spftree, vertex, lfa_list,
diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c
index 5387f3703..63b4edb1e 100644
--- a/isisd/isis_lsp.c
+++ b/isisd/isis_lsp.c
@@ -68,6 +68,8 @@ static void lsp_l2_refresh_pseudo(struct thread *thread);
static void lsp_destroy(struct isis_lsp *lsp);
+static bool device_startup;
+
int lsp_id_cmp(uint8_t *id1, uint8_t *id2)
{
return memcmp(id1, id2, ISIS_SYS_ID_LEN + 2);
@@ -437,6 +439,21 @@ bool isis_level2_adj_up(struct isis_area *area)
return false;
}
+/*
+ * Unset the overload bit after the timer expires
+ */
+void set_overload_on_start_timer(struct thread *thread)
+{
+ struct isis_area *area = THREAD_ARG(thread);
+ assert(area);
+
+ area->t_overload_on_startup_timer = NULL;
+
+ /* Check if set-overload-bit is not currently configured */
+ if (!area->overload_configured)
+ isis_area_overload_bit_set(area, false);
+}
+
static void isis_reset_attach_bit(struct isis_adjacency *adj)
{
struct isis_area *area = adj->circuit->area;
@@ -1355,6 +1372,7 @@ int lsp_generate(struct isis_area *area, int level)
uint32_t seq_num = 0;
uint8_t lspid[ISIS_SYS_ID_LEN + 2];
uint16_t rem_lifetime, refresh_time;
+ uint32_t overload_time;
if ((area == NULL) || (area->is_type & level) != level)
return ISIS_ERROR;
@@ -1363,6 +1381,18 @@ int lsp_generate(struct isis_area *area, int level)
memcpy(&lspid, area->isis->sysid, ISIS_SYS_ID_LEN);
+ /* Check if device should be overloaded on startup */
+ if (device_startup) {
+ overload_time = isis_restart_read_overload_time(area);
+ if (overload_time > 0) {
+ isis_area_overload_bit_set(area, true);
+ thread_add_timer(master, set_overload_on_start_timer,
+ area, overload_time,
+ &area->t_overload_on_startup_timer);
+ }
+ device_startup = false;
+ }
+
/* only builds the lsp if the area shares the level */
oldlsp = lsp_search(&area->lspdb[level - 1], lspid);
if (oldlsp) {
@@ -2373,6 +2403,7 @@ int isis_lsp_iterate_is_reach(struct isis_lsp *lsp, uint16_t mtid,
void lsp_init(void)
{
+ device_startup = true;
hook_register(isis_adj_state_change_hook,
lsp_handle_adj_state_change);
}
diff --git a/isisd/isis_lsp.h b/isisd/isis_lsp.h
index b13b2a35e..d7762324d 100644
--- a/isisd/isis_lsp.h
+++ b/isisd/isis_lsp.h
@@ -66,6 +66,7 @@ DECLARE_RBTREE_UNIQ(lspdb, struct isis_lsp, dbe, lspdb_compare);
void lsp_db_init(struct lspdb_head *head);
void lsp_db_fini(struct lspdb_head *head);
void lsp_tick(struct thread *thread);
+void set_overload_on_start_timer(struct thread *thread);
int lsp_generate(struct isis_area *area, int level);
#define lsp_regenerate_schedule(area, level, all_pseudo) \
diff --git a/isisd/isis_nb.c b/isisd/isis_nb.c
index a2ba33d07..4f4e6dc73 100644
--- a/isisd/isis_nb.c
+++ b/isisd/isis_nb.c
@@ -81,11 +81,18 @@ const struct frr_yang_module_info frr_isisd_info = {
},
},
{
- .xpath = "/frr-isisd:isis/instance/overload",
+ .xpath = "/frr-isisd:isis/instance/overload/enabled",
.cbs = {
.cli_show = cli_show_isis_overload,
- .modify = isis_instance_overload_modify,
- },
+ .modify = isis_instance_overload_enabled_modify,
+ }
+ },
+ {
+ .xpath = "/frr-isisd:isis/instance/overload/on-startup",
+ .cbs = {
+ .cli_show = cli_show_isis_overload_on_startup,
+ .modify = isis_instance_overload_on_startup_modify,
+ }
},
{
.xpath = "/frr-isisd:isis/instance/metric-style",
diff --git a/isisd/isis_nb.h b/isisd/isis_nb.h
index 00ca8be3b..a9f2eaea9 100644
--- a/isisd/isis_nb.h
+++ b/isisd/isis_nb.h
@@ -37,7 +37,8 @@ int isis_instance_dynamic_hostname_modify(struct nb_cb_modify_args *args);
int isis_instance_attached_send_modify(struct nb_cb_modify_args *args);
int isis_instance_attached_receive_modify(struct nb_cb_modify_args *args);
int isis_instance_attached_modify(struct nb_cb_modify_args *args);
-int isis_instance_overload_modify(struct nb_cb_modify_args *args);
+int isis_instance_overload_enabled_modify(struct nb_cb_modify_args *args);
+int isis_instance_overload_on_startup_modify(struct nb_cb_modify_args *args);
int isis_instance_metric_style_modify(struct nb_cb_modify_args *args);
int isis_instance_purge_originator_modify(struct nb_cb_modify_args *args);
int isis_instance_lsp_mtu_modify(struct nb_cb_modify_args *args);
@@ -442,6 +443,9 @@ void cli_show_isis_attached_receive(struct vty *vty,
bool show_defaults);
void cli_show_isis_overload(struct vty *vty, const struct lyd_node *dnode,
bool show_defaults);
+void cli_show_isis_overload_on_startup(struct vty *vty,
+ const struct lyd_node *dnode,
+ bool show_defaults);
void cli_show_isis_metric_style(struct vty *vty, const struct lyd_node *dnode,
bool show_defaults);
void cli_show_isis_area_pwd(struct vty *vty, const struct lyd_node *dnode,
diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c
index e0decf48f..1b7663fcf 100644
--- a/isisd/isis_nb_config.c
+++ b/isisd/isis_nb_config.c
@@ -336,9 +336,9 @@ int isis_instance_attached_modify(struct nb_cb_modify_args *args)
}
/*
- * XPath: /frr-isisd:isis/instance/overload
+ * XPath: /frr-isisd:isis/instance/overload/enabled
*/
-int isis_instance_overload_modify(struct nb_cb_modify_args *args)
+int isis_instance_overload_enabled_modify(struct nb_cb_modify_args *args)
{
struct isis_area *area;
bool overload;
@@ -348,12 +348,32 @@ int isis_instance_overload_modify(struct nb_cb_modify_args *args)
area = nb_running_get_entry(args->dnode, NULL, true);
overload = yang_dnode_get_bool(args->dnode, NULL);
+ area->overload_configured = overload;
+
isis_area_overload_bit_set(area, overload);
return NB_OK;
}
/*
+ * XPath: /frr-isisd:isis/instance/overload/on-startup
+ */
+int isis_instance_overload_on_startup_modify(struct nb_cb_modify_args *args)
+{
+ struct isis_area *area;
+ uint32_t overload_time;
+
+ if (args->event != NB_EV_APPLY)
+ return NB_OK;
+
+ overload_time = yang_dnode_get_uint32(args->dnode, NULL);
+ area = nb_running_get_entry(args->dnode, NULL, true);
+ isis_area_overload_on_startup_set(area, overload_time);
+
+ return NB_OK;
+}
+
+/*
* XPath: /frr-isisd:isis/instance/metric-style
*/
int isis_instance_metric_style_modify(struct nb_cb_modify_args *args)
diff --git a/isisd/isis_route.c b/isisd/isis_route.c
index 9f8f639e5..c7dc9b7c4 100644
--- a/isisd/isis_route.c
+++ b/isisd/isis_route.c
@@ -91,11 +91,18 @@ static struct isis_nexthop *nexthoplookup(struct list *nexthops, int family,
struct isis_nexthop *nh;
for (ALL_LIST_ELEMENTS_RO(nexthops, node, nh)) {
- if (nh->family != family)
- continue;
if (nh->ifindex != ifindex)
continue;
+ /* if the IP is unspecified, return the first nexthop found on
+ * the interface
+ */
+ if (!ip)
+ return nh;
+
+ if (nh->family != family)
+ continue;
+
switch (family) {
case AF_INET:
if (IPV4_ADDR_CMP(&nh->ip.ipv4, &ip->ipv4))
@@ -459,25 +466,33 @@ void isis_route_delete(struct isis_area *area, struct route_node *rode,
route_unlock_node(rode);
}
+static void isis_route_remove_previous_sid(struct isis_area *area,
+ struct prefix *prefix,
+ struct isis_route_info *route_info)
+{
+ /*
+ * Explicitly uninstall previous Prefix-SID label if it has
+ * changed or was removed.
+ */
+ if (route_info->sr_previous.present &&
+ (!route_info->sr.present ||
+ route_info->sr_previous.label != route_info->sr.label))
+ isis_zebra_prefix_sid_uninstall(area, prefix, route_info,
+ &route_info->sr_previous);
+}
+
static void isis_route_update(struct isis_area *area, struct prefix *prefix,
struct prefix_ipv6 *src_p,
struct isis_route_info *route_info)
{
+ if (area == NULL)
+ return;
+
if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ACTIVE)) {
if (CHECK_FLAG(route_info->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED))
return;
- /*
- * Explicitly uninstall previous Prefix-SID label if it has
- * changed or was removed.
- */
- if (route_info->sr_previous.present
- && (!route_info->sr.present
- || route_info->sr_previous.label
- != route_info->sr.label))
- isis_zebra_prefix_sid_uninstall(
- area, prefix, route_info,
- &route_info->sr_previous);
+ isis_route_remove_previous_sid(area, prefix, route_info);
/* Install route. */
isis_zebra_route_add_route(area->isis, prefix, src_p,
@@ -724,3 +739,54 @@ void isis_route_invalidate_table(struct isis_area *area,
UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ACTIVE);
}
}
+
+void isis_route_switchover_nexthop(struct isis_area *area,
+ struct route_table *table, int family,
+ union g_addr *nexthop_addr,
+ ifindex_t ifindex)
+{
+ const char *ifname = NULL, *vrfname = NULL;
+ struct isis_route_info *rinfo;
+ struct prefix_ipv6 *src_p;
+ struct route_node *rnode;
+ vrf_id_t vrf_id;
+ struct prefix *prefix;
+
+ if (IS_DEBUG_EVENTS) {
+ if (area && area->isis) {
+ vrf_id = area->isis->vrf_id;
+ vrfname = vrf_id_to_name(vrf_id);
+ ifname = ifindex2ifname(ifindex, vrf_id);
+ }
+ zlog_debug("%s: initiating fast-reroute %s on VRF %s iface %s",
+ __func__, family2str(family), vrfname ? vrfname : "",
+ ifname ? ifname : "");
+ }
+
+ for (rnode = route_top(table); rnode;
+ rnode = srcdest_route_next(rnode)) {
+ if (!rnode->info)
+ continue;
+ rinfo = rnode->info;
+
+ if (!rinfo->backup)
+ continue;
+
+ if (!nexthoplookup(rinfo->nexthops, family, nexthop_addr,
+ ifindex))
+ continue;
+
+ srcdest_rnode_prefixes(rnode, (const struct prefix **)&prefix,
+ (const struct prefix **)&src_p);
+
+ /* Switchover route. */
+ isis_route_remove_previous_sid(area, prefix, rinfo);
+ UNSET_FLAG(rinfo->flag, ISIS_ROUTE_FLAG_ZEBRA_SYNCED);
+ isis_route_update(area, prefix, src_p, rinfo->backup);
+
+ isis_route_info_delete(rinfo);
+
+ rnode->info = NULL;
+ route_unlock_node(rnode);
+ }
+}
diff --git a/isisd/isis_route.h b/isisd/isis_route.h
index 0e206d08f..a0e0500ae 100644
--- a/isisd/isis_route.h
+++ b/isisd/isis_route.h
@@ -86,4 +86,9 @@ void isis_route_invalidate_table(struct isis_area *area,
void isis_route_node_cleanup(struct route_table *table,
struct route_node *node);
+void isis_route_switchover_nexthop(struct isis_area *area,
+ struct route_table *table, int family,
+ union g_addr *nexthop_addr,
+ ifindex_t ifindex);
+
#endif /* _ZEBRA_ISIS_ROUTE_H */
diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c
index bdd323e1a..0d1a5db0d 100644
--- a/isisd/isis_spf.c
+++ b/isisd/isis_spf.c
@@ -1851,6 +1851,15 @@ void isis_spf_invalidate_routes(struct isis_spftree *tree)
tree->route_table_backup->cleanup = isis_route_node_cleanup;
}
+void isis_spf_switchover_routes(struct isis_area *area,
+ struct isis_spftree **trees, int family,
+ union g_addr *nexthop_ip, ifindex_t ifindex,
+ int level)
+{
+ isis_route_switchover_nexthop(area, trees[level - 1]->route_table,
+ family, nexthop_ip, ifindex);
+}
+
static void isis_run_spf_cb(struct thread *thread)
{
struct isis_spf_run *run = THREAD_ARG(thread);
@@ -1922,9 +1931,19 @@ void isis_spf_timer_free(void *run)
int _isis_spf_schedule(struct isis_area *area, int level,
const char *func, const char *file, int line)
{
- struct isis_spftree *spftree = area->spftree[SPFTREE_IPV4][level - 1];
- time_t now = monotime(NULL);
- int diff = now - spftree->last_run_monotime;
+ struct isis_spftree *spftree;
+ time_t now;
+ long tree_diff, diff;
+ int tree;
+
+ now = monotime(NULL);
+ diff = 0;
+ for (tree = SPFTREE_IPV4; tree < SPFTREE_COUNT; tree++) {
+ spftree = area->spftree[tree][level - 1];
+ tree_diff = difftime(now - spftree->last_run_monotime, 0);
+ if (tree_diff != now && (diff == 0 || tree_diff < diff))
+ diff = tree_diff;
+ }
if (CHECK_FLAG(im->options, F_ISIS_UNIT_TEST))
return 0;
@@ -1934,7 +1953,7 @@ int _isis_spf_schedule(struct isis_area *area, int level,
if (IS_DEBUG_SPF_EVENTS) {
zlog_debug(
- "ISIS-SPF (%s) L%d SPF schedule called, lastrun %d sec ago Caller: %s %s:%d",
+ "ISIS-SPF (%s) L%d SPF schedule called, lastrun %ld sec ago Caller: %s %s:%d",
area->area_tag, level, diff, func, file, line);
}
diff --git a/isisd/isis_spf.h b/isisd/isis_spf.h
index 815db7b22..3fa5182ba 100644
--- a/isisd/isis_spf.h
+++ b/isisd/isis_spf.h
@@ -60,6 +60,10 @@ struct isis_vertex *isis_spf_prefix_sid_lookup(struct isis_spftree *spftree,
void isis_spf_invalidate_routes(struct isis_spftree *tree);
void isis_spf_verify_routes(struct isis_area *area,
struct isis_spftree **trees);
+void isis_spf_switchover_routes(struct isis_area *area,
+ struct isis_spftree **trees, int family,
+ union g_addr *nexthop_ip, ifindex_t ifindex,
+ int level);
void isis_spftree_del(struct isis_spftree *spftree);
void spftree_area_init(struct isis_area *area);
void spftree_area_del(struct isis_area *area);
diff --git a/isisd/isis_sr.c b/isisd/isis_sr.c
index f70840a63..707bd162f 100644
--- a/isisd/isis_sr.c
+++ b/isisd/isis_sr.c
@@ -1057,8 +1057,9 @@ static void show_node(struct vty *vty, struct isis_area *area, int level)
}
DEFUN(show_sr_node, show_sr_node_cmd,
- "show isis segment-routing node",
- SHOW_STR PROTO_HELP
+ "show " PROTO_NAME " segment-routing node",
+ SHOW_STR
+ PROTO_HELP
"Segment-Routing\n"
"Segment-Routing node\n")
{
diff --git a/isisd/isis_te.c b/isisd/isis_te.c
index 0093279cd..155d1e6fe 100644
--- a/isisd/isis_te.c
+++ b/isisd/isis_te.c
@@ -66,6 +66,8 @@
DEFINE_MTYPE_STATIC(ISISD, ISIS_MPLS_TE, "ISIS MPLS_TE parameters");
+static void isis_mpls_te_circuit_ip_update(struct isis_circuit *circuit);
+
/*------------------------------------------------------------------------*
* Following are control functions for MPLS-TE parameters management.
*------------------------------------------------------------------------*/
@@ -111,9 +113,13 @@ void isis_mpls_te_create(struct isis_area *area)
if (area->mta->ted)
isis_te_init_ted(area);
- /* Update Extended TLVs according to Interface link parameters */
- for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit))
+ /* Update Extended TLVs according to Interface link parameters
+ * and neighbor IP addresses
+ */
+ for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
isis_link_params_update(circuit, circuit->interface);
+ isis_mpls_te_circuit_ip_update(circuit);
+ }
}
/**
@@ -132,7 +138,7 @@ void isis_mpls_te_disable(struct isis_area *area)
area->mta->status = disable;
/* Remove Link State Database */
- ls_ted_del_all(&area->mta->ted);
+ ls_ted_clean(area->mta->ted);
/* Disable Extended SubTLVs on all circuit */
for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
@@ -336,16 +342,12 @@ void isis_link_params_update(struct isis_circuit *circuit,
return;
}
-static int isis_mpls_te_adj_ip_enabled(struct isis_adjacency *adj, int family,
- bool global)
+static int _isis_mpls_te_adj_ip_enabled(struct isis_adjacency *adj, int family,
+ bool global)
{
struct isis_circuit *circuit;
struct isis_ext_subtlvs *ext;
- /* Sanity Check */
- if (!adj || !adj->circuit)
- return 0;
-
circuit = adj->circuit;
/* Check that MPLS TE is enabled */
@@ -366,6 +368,12 @@ static int isis_mpls_te_adj_ip_enabled(struct isis_adjacency *adj, int family,
}
break;
case AF_INET6:
+ /* Nothing to do for link-local addresses - ie. not global.
+ * https://datatracker.ietf.org/doc/html/rfc6119#section-3.1.1
+ * Because the IPv6 traffic engineering TLVs present in LSPs are
+ * propagated across networks, they MUST NOT use link-local
+ * addresses.
+ */
if (!global)
return 0;
@@ -381,22 +389,32 @@ static int isis_mpls_te_adj_ip_enabled(struct isis_adjacency *adj, int family,
return 0;
}
- /* Update LSP */
- lsp_regenerate_schedule(circuit->area, circuit->is_type, 0);
-
return 0;
}
-static int isis_mpls_te_adj_ip_disabled(struct isis_adjacency *adj, int family,
- bool global)
+static int isis_mpls_te_adj_ip_enabled(struct isis_adjacency *adj, int family,
+ bool global)
{
- struct isis_circuit *circuit;
- struct isis_ext_subtlvs *ext;
+ int ret;
/* Sanity Check */
- if (!adj || !adj->circuit || !adj->circuit->ext)
+ if (!adj || !adj->circuit)
return 0;
+ ret = _isis_mpls_te_adj_ip_enabled(adj, family, global);
+
+ /* Update LSP */
+ lsp_regenerate_schedule(adj->circuit->area, adj->circuit->is_type, 0);
+
+ return ret;
+}
+
+static int _isis_mpls_te_adj_ip_disabled(struct isis_adjacency *adj, int family,
+ bool global)
+{
+ struct isis_circuit *circuit;
+ struct isis_ext_subtlvs *ext;
+
circuit = adj->circuit;
/* Check that MPLS TE is enabled */
@@ -422,12 +440,59 @@ static int isis_mpls_te_adj_ip_disabled(struct isis_adjacency *adj, int family,
return 0;
}
+ return 0;
+}
+
+static int isis_mpls_te_adj_ip_disabled(struct isis_adjacency *adj, int family,
+ bool global)
+{
+ int ret;
+
+ /* Sanity Check */
+ if (!adj || !adj->circuit || !adj->circuit->ext)
+ return 0;
+
+ ret = _isis_mpls_te_adj_ip_disabled(adj, family, global);
+
/* Update LSP */
- lsp_regenerate_schedule(circuit->area, circuit->is_type, 0);
+ lsp_regenerate_schedule(adj->circuit->area, adj->circuit->is_type, 0);
- return 0;
+ return ret;
}
+static void isis_mpls_te_circuit_ip_update(struct isis_circuit *circuit)
+{
+ struct isis_adjacency *adj;
+
+ /* https://datatracker.ietf.org/doc/html/rfc6119#section-3.2.3
+ * This sub-TLV of the Extended IS Reachability TLV is used for point-
+ * to-point links
+ */
+ if (circuit->circ_type != CIRCUIT_T_P2P)
+ return;
+
+ adj = circuit->u.p2p.neighbor;
+
+ if (!adj)
+ return;
+
+ /* Nothing to do for link-local addresses.
+ * https://datatracker.ietf.org/doc/html/rfc6119#section-3.1.1
+ * Because the IPv6 traffic engineering TLVs present in LSPs are
+ * propagated across networks, they MUST NOT use link-local addresses.
+ */
+ if (adj->ipv4_address_count > 0)
+ _isis_mpls_te_adj_ip_enabled(adj, AF_INET, false);
+ else
+ _isis_mpls_te_adj_ip_disabled(adj, AF_INET, false);
+
+ if (adj->global_ipv6_count > 0)
+ _isis_mpls_te_adj_ip_enabled(adj, AF_INET6, true);
+ else
+ _isis_mpls_te_adj_ip_disabled(adj, AF_INET6, true);
+}
+
+
int isis_mpls_te_update(struct interface *ifp)
{
struct isis_circuit *circuit;
diff --git a/isisd/isisd.c b/isisd/isisd.c
index 54e6be597..cd0852547 100644
--- a/isisd/isisd.c
+++ b/isisd/isisd.c
@@ -723,7 +723,7 @@ void isis_vrf_init(void)
vrf_cmd_init(NULL);
}
-void isis_terminate()
+void isis_terminate(void)
{
struct isis *isis;
struct listnode *node, *nnode;
@@ -1700,6 +1700,8 @@ DEFUN_NOSH (show_debugging,
if (IS_DEBUG_LFA)
print_debug(vty, DEBUG_LFA, 1);
+ cmd_show_lib_debugs(vty);
+
return CMD_SUCCESS;
}
@@ -2743,7 +2745,6 @@ static void show_isis_database_json(struct json_object *json, const char *sysid_
struct isis_area *area;
int level;
struct json_object *tag_area_json,*area_json, *lsp_json, *area_arr_json, *arr_json;
- uint8_t area_cnt = 0;
if (isis->area_list->count == 0)
return;
@@ -2768,7 +2769,6 @@ static void show_isis_database_json(struct json_object *json, const char *sysid_
json_object_array_add(arr_json, lsp_json);
}
json_object_array_add(area_arr_json, area_json);
- area_cnt++;
}
}
@@ -3090,6 +3090,25 @@ void isis_area_verify_routes(struct isis_area *area)
isis_spf_verify_routes(area, area->spftree[tree]);
}
+void isis_area_switchover_routes(struct isis_area *area, int family,
+ union g_addr *nexthop_ip, ifindex_t ifindex,
+ int level)
+{
+ int tree;
+
+ /* TODO SPFTREE_DSTSRC */
+ if (family == AF_INET)
+ tree = SPFTREE_IPV4;
+ else if (family == AF_INET6)
+ tree = SPFTREE_IPV6;
+ else
+ return;
+
+ isis_spf_switchover_routes(area, area->spftree[tree], family,
+ nexthop_ip, ifindex, level);
+}
+
+
static void area_resign_level(struct isis_area *area, int level)
{
isis_area_invalidate_routes(area, level);
@@ -3196,9 +3215,15 @@ void isis_area_overload_bit_set(struct isis_area *area, bool overload_bit)
if (new_overload_bit != area->overload_bit) {
area->overload_bit = new_overload_bit;
-
- if (new_overload_bit)
+ if (new_overload_bit) {
area->overload_counter++;
+ } else {
+ /* Cancel overload on startup timer if it's running */
+ if (area->t_overload_on_startup_timer) {
+ THREAD_OFF(area->t_overload_on_startup_timer);
+ area->t_overload_on_startup_timer = NULL;
+ }
+ }
#ifndef FABRICD
hook_call(isis_hook_db_overload, area);
@@ -3211,6 +3236,109 @@ void isis_area_overload_bit_set(struct isis_area *area, bool overload_bit)
#endif /* ifndef FABRICD */
}
+void isis_area_overload_on_startup_set(struct isis_area *area,
+ uint32_t startup_time)
+{
+ if (area->overload_on_startup_time != startup_time) {
+ area->overload_on_startup_time = startup_time;
+ isis_restart_write_overload_time(area, startup_time);
+ }
+}
+
+/*
+ * Returns the path of the file (non-volatile memory) that contains restart
+ * information.
+ */
+char *isis_restart_filepath(void)
+{
+ static char filepath[MAXPATHLEN];
+ snprintf(filepath, sizeof(filepath), ISISD_RESTART, "");
+ return filepath;
+}
+
+/*
+ * Record in non-volatile memory the overload on startup time.
+ */
+void isis_restart_write_overload_time(struct isis_area *isis_area,
+ uint32_t overload_time)
+{
+ char *filepath;
+ const char *area_name;
+ json_object *json;
+ json_object *json_areas;
+ json_object *json_area;
+
+ filepath = isis_restart_filepath();
+ area_name = isis_area->area_tag;
+
+ json = json_object_from_file(filepath);
+ if (json == NULL)
+ json = json_object_new_object();
+
+ json_object_object_get_ex(json, "areas", &json_areas);
+ if (!json_areas) {
+ json_areas = json_object_new_object();
+ json_object_object_add(json, "areas", json_areas);
+ }
+
+ json_object_object_get_ex(json_areas, area_name, &json_area);
+ if (!json_area) {
+ json_area = json_object_new_object();
+ json_object_object_add(json_areas, area_name, json_area);
+ }
+
+ json_object_int_add(json_area, "overload_time",
+ isis_area->overload_on_startup_time);
+ json_object_to_file_ext(filepath, json, JSON_C_TO_STRING_PRETTY);
+ json_object_free(json);
+}
+
+/*
+ * Fetch from non-volatile memory the overload on startup time.
+ */
+uint32_t isis_restart_read_overload_time(struct isis_area *isis_area)
+{
+ char *filepath;
+ const char *area_name;
+ json_object *json;
+ json_object *json_areas;
+ json_object *json_area;
+ json_object *json_overload_time;
+ uint32_t overload_time = 0;
+
+ filepath = isis_restart_filepath();
+ area_name = isis_area->area_tag;
+
+ json = json_object_from_file(filepath);
+ if (json == NULL)
+ json = json_object_new_object();
+
+ json_object_object_get_ex(json, "areas", &json_areas);
+ if (!json_areas) {
+ json_areas = json_object_new_object();
+ json_object_object_add(json, "areas", json_areas);
+ }
+
+ json_object_object_get_ex(json_areas, area_name, &json_area);
+ if (!json_area) {
+ json_area = json_object_new_object();
+ json_object_object_add(json_areas, area_name, json_area);
+ }
+
+ json_object_object_get_ex(json_area, "overload_time",
+ &json_overload_time);
+ if (json_overload_time) {
+ overload_time = json_object_get_int(json_overload_time);
+ }
+
+ json_object_object_del(json_areas, area_name);
+
+ json_object_to_file_ext(filepath, json, JSON_C_TO_STRING_PRETTY);
+ json_object_free(json);
+
+ return overload_time;
+}
+
void isis_area_attached_bit_send_set(struct isis_area *area, bool attached_bit)
{
diff --git a/isisd/isisd.h b/isisd/isisd.h
index 4951e5809..38f20b211 100644
--- a/isisd/isisd.h
+++ b/isisd/isisd.h
@@ -142,6 +142,7 @@ struct isis_area {
struct flags flags;
struct thread *t_tick; /* LSP walker */
struct thread *t_lsp_refresh[ISIS_LEVELS];
+ struct thread *t_overload_on_startup_timer;
struct timeval last_lsp_refresh_event[ISIS_LEVELS];
struct thread *t_rlfa_rib_update;
/* t_lsp_refresh is used in two ways:
@@ -180,7 +181,9 @@ struct isis_area {
char is_type; /* level-1 level-1-2 or level-2-only */
/* are we overloaded? */
char overload_bit;
+ bool overload_configured;
uint32_t overload_counter;
+ uint32_t overload_on_startup_time;
/* L1/L2 router identifier for inter-area traffic */
char attached_bit_send;
char attached_bit_rcv_ignore;
@@ -288,8 +291,13 @@ struct isis_lsp *lsp_for_sysid(struct lspdb_head *head, const char *sysid_str,
void isis_area_invalidate_routes(struct isis_area *area, int levels);
void isis_area_verify_routes(struct isis_area *area);
+void isis_area_switchover_routes(struct isis_area *area, int family,
+ union g_addr *nexthop_ip, ifindex_t ifindex,
+ int level);
void isis_area_overload_bit_set(struct isis_area *area, bool overload_bit);
+void isis_area_overload_on_startup_set(struct isis_area *area,
+ uint32_t startup_time);
void isis_area_attached_bit_send_set(struct isis_area *area, bool attached_bit);
void isis_area_attached_bit_receive_set(struct isis_area *area,
bool attached_bit);
@@ -315,7 +323,10 @@ void show_isis_database_lspdb_json(struct json_object *json,
void show_isis_database_lspdb_vty(struct vty *vty, struct isis_area *area,
int level, struct lspdb_head *lspdb,
const char *argv, int ui_level);
-
+char *isis_restart_filepath(void);
+void isis_restart_write_overload_time(struct isis_area *isis_area,
+ uint32_t overload_time);
+uint32_t isis_restart_read_overload_time(struct isis_area *isis_area);
/* YANG paths */
#define ISIS_INSTANCE "/frr-isisd:isis/instance"
#define ISIS_SR "/frr-isisd:isis/instance/segment-routing"
diff --git a/isisd/subdir.am b/isisd/subdir.am
index 3e5816c16..dabf6a925 100644
--- a/isisd/subdir.am
+++ b/isisd/subdir.am
@@ -5,16 +5,6 @@
if ISISD
noinst_LIBRARIES += isisd/libisis.a
sbin_PROGRAMS += isisd/isisd
-vtysh_scan += \
- isisd/isis_cli.c \
- isisd/isis_ldp_sync.c \
- 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
vtysh_daemons += isisd
if SNMP
module_LTLIBRARIES += isisd/isisd_snmp.la
@@ -25,18 +15,6 @@ endif
if FABRICD
noinst_LIBRARIES += isisd/libfabric.a
sbin_PROGRAMS += isisd/fabricd
-if !ISISD
-vtysh_scan += \
- isisd/isis_cli.c \
- isisd/isis_ldp_sync.c \
- 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
-endif
vtysh_daemons += fabricd
endif
diff --git a/ldpd/ldp_vty_cmds.c b/ldpd/ldp_vty_cmds.c
index 11d6930f0..33e6b297c 100644
--- a/ldpd/ldp_vty_cmds.c
+++ b/ldpd/ldp_vty_cmds.c
@@ -25,9 +25,7 @@
#include "ldpd/ldpd.h"
#include "ldpd/ldp_vty.h"
-#ifndef VTYSH_EXTRACT_PL
#include "ldpd/ldp_vty_cmds_clippy.c"
-#endif
DEFPY_NOSH(ldp_mpls_ldp,
ldp_mpls_ldp_cmd,
@@ -246,7 +244,7 @@ DEFPY (ldp_allow_broken_lsps,
"[no] install allow-broken-lsps",
NO_STR
"install lsps\n"
- "if no remote-label install with imp-null")
+ "if no remote-label install with imp-null\n")
{
return (ldp_vty_allow_broken_lsp(vty, no));
}
@@ -774,7 +772,11 @@ DEFPY_NOSH (ldp_show_debugging_mpls_ldp,
"MPLS information\n"
"Label Distribution Protocol\n")
{
- return (ldp_vty_show_debugging(vty));
+ ldp_vty_show_debugging(vty);
+
+ cmd_show_lib_debugs(vty);
+
+ return CMD_SUCCESS;
}
static void
diff --git a/ldpd/neighbor.c b/ldpd/neighbor.c
index e1db9e8e1..6d6c7d00c 100644
--- a/ldpd/neighbor.c
+++ b/ldpd/neighbor.c
@@ -359,8 +359,7 @@ nbr_find_ldpid(uint32_t lsr_id)
return (RB_FIND(nbr_id_head, &nbrs_by_id, &n));
}
-struct nbr *
-nbr_get_first_ldpid()
+struct nbr *nbr_get_first_ldpid(void)
{
return (RB_MIN(nbr_id_head, &nbrs_by_id));
}
diff --git a/ldpd/subdir.am b/ldpd/subdir.am
index 083effb70..0b948adb6 100644
--- a/ldpd/subdir.am
+++ b/ldpd/subdir.am
@@ -5,7 +5,6 @@
if LDPD
noinst_LIBRARIES += ldpd/libldp.a
sbin_PROGRAMS += ldpd/ldpd
-vtysh_scan += ldpd/ldp_vty_cmds.c
vtysh_daemons += ldpd
man8 += $(MANBUILD)/frr-ldpd.8
endif
diff --git a/lib/agentx.c b/lib/agentx.c
index 4c087219c..6c2923fcf 100644
--- a/lib/agentx.c
+++ b/lib/agentx.c
@@ -48,8 +48,6 @@ static void agentx_events_update(void);
static void agentx_timeout(struct thread *t)
{
- timeout_thr = NULL;
-
snmp_timeout();
run_alarms();
netsnmp_check_outstanding_agent_requests();
diff --git a/lib/command.c b/lib/command.c
index a23afb1e4..1fae32a04 100644
--- a/lib/command.c
+++ b/lib/command.c
@@ -48,6 +48,7 @@
#include "lib_errors.h"
#include "northbound_cli.h"
#include "network.h"
+#include "routemap.h"
#include "frrscript.h"
@@ -264,8 +265,7 @@ void install_node(struct cmd_node *node)
node->cmdgraph = graph_new();
node->cmd_vector = vector_init(VECTOR_MIN_SIZE);
// add start node
- struct cmd_token *token =
- cmd_token_new(START_TKN, CMD_ATTR_NORMAL, NULL, NULL);
+ struct cmd_token *token = cmd_token_new(START_TKN, 0, NULL, NULL);
graph_new_node(node->cmdgraph, token,
(void (*)(void *)) & cmd_token_del);
@@ -325,7 +325,7 @@ void _install_element(enum node_type ntype, const struct cmd_element *cmd)
if (cnode->graph_built || !defer_cli_tree) {
struct graph *graph = graph_new();
struct cmd_token *token =
- cmd_token_new(START_TKN, CMD_ATTR_NORMAL, NULL, NULL);
+ cmd_token_new(START_TKN, 0, NULL, NULL);
graph_new_node(graph, token,
(void (*)(void *)) & cmd_token_del);
@@ -348,8 +348,7 @@ static void cmd_finalize_iter(struct hash_bucket *hb, void *arg)
struct cmd_node *cnode = arg;
const struct cmd_element *cmd = hb->data;
struct graph *graph = graph_new();
- struct cmd_token *token =
- cmd_token_new(START_TKN, CMD_ATTR_NORMAL, NULL, NULL);
+ struct cmd_token *token = cmd_token_new(START_TKN, 0, NULL, NULL);
graph_new_node(graph, token, (void (*)(void *)) & cmd_token_del);
@@ -404,7 +403,7 @@ void uninstall_element(enum node_type ntype, const struct cmd_element *cmd)
if (cnode->graph_built) {
struct graph *graph = graph_new();
struct cmd_token *token =
- cmd_token_new(START_TKN, CMD_ATTR_NORMAL, NULL, NULL);
+ cmd_token_new(START_TKN, 0, NULL, NULL);
graph_new_node(graph, token,
(void (*)(void *)) & cmd_token_del);
@@ -990,7 +989,7 @@ static int cmd_execute_command_real(vector vline, enum cmd_filter_type filter,
* Perform pending commit (if any) before executing
* non-YANG command.
*/
- if (matched_element->attr != CMD_ATTR_YANG)
+ if (!(matched_element->attr & CMD_ATTR_YANG))
(void)nb_cli_pending_commit_check(vty);
}
@@ -1471,8 +1470,7 @@ static void permute(struct graph_node *start, struct vty *vty)
for (unsigned int i = 0; i < vector_active(start->to); i++) {
struct graph_node *gn = vector_slot(start->to, i);
struct cmd_token *tok = gn->data;
- if (tok->attr == CMD_ATTR_HIDDEN
- || tok->attr == CMD_ATTR_DEPRECATED)
+ if (tok->attr & CMD_ATTR_HIDDEN)
continue;
else if (tok->type == END_TKN || gn == start) {
vty_out(vty, " ");
@@ -1561,9 +1559,8 @@ int cmd_list_cmds(struct vty *vty, int do_permute)
const struct cmd_element *element = NULL;
for (unsigned int i = 0; i < vector_active(node->cmd_vector);
i++)
- if ((element = vector_slot(node->cmd_vector, i))
- && element->attr != CMD_ATTR_DEPRECATED
- && element->attr != CMD_ATTR_HIDDEN) {
+ if ((element = vector_slot(node->cmd_vector, i)) &&
+ !(element->attr & CMD_ATTR_HIDDEN)) {
vty_out(vty, " ");
print_cmd(vty, element->string);
}
@@ -2446,6 +2443,11 @@ const char *host_config_get(void)
return host.config;
}
+void cmd_show_lib_debugs(struct vty *vty)
+{
+ route_map_show_debug(vty);
+}
+
void install_default(enum node_type node)
{
_install_element(node, &config_exit_cmd);
diff --git a/lib/command.h b/lib/command.h
index b701d4d0e..0f9715e81 100644
--- a/lib/command.h
+++ b/lib/command.h
@@ -251,9 +251,6 @@ struct cmd_node {
/* Argc max counts. */
#define CMD_ARGC_MAX 256
-/* Turn off these macros when using cpp with extract.pl */
-#ifndef VTYSH_EXTRACT_PL
-
/* helper defines for end-user DEFUN* macros */
#define DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attrs, dnum) \
static const struct cmd_element cmdname = { \
@@ -280,17 +277,18 @@ struct cmd_node {
int argc __attribute__((unused)), \
struct cmd_token *argv[] __attribute__((unused)))
-#define DEFPY(funcname, cmdname, cmdstr, helpstr) \
- DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, 0) \
- funcdecl_##funcname
-
-#define DEFPY_NOSH(funcname, cmdname, cmdstr, helpstr) \
- DEFPY(funcname, cmdname, cmdstr, helpstr)
+/* DEFPY variants */
#define DEFPY_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \
DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) \
funcdecl_##funcname
+#define DEFPY(funcname, cmdname, cmdstr, helpstr) \
+ DEFPY_ATTR(funcname, cmdname, cmdstr, helpstr, 0)
+
+#define DEFPY_NOSH(funcname, cmdname, cmdstr, helpstr) \
+ DEFPY_ATTR(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_NOSH)
+
#define DEFPY_HIDDEN(funcname, cmdname, cmdstr, helpstr) \
DEFPY_ATTR(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN)
@@ -298,18 +296,19 @@ struct cmd_node {
DEFPY_ATTR(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_YANG)
#define DEFPY_YANG_NOSH(funcname, cmdname, cmdstr, helpstr) \
- DEFPY_YANG(funcname, cmdname, cmdstr, helpstr)
+ DEFPY_ATTR(funcname, cmdname, cmdstr, helpstr, \
+ CMD_ATTR_YANG | CMD_ATTR_NOSH)
-#define DEFUN(funcname, cmdname, cmdstr, helpstr) \
- DEFUN_CMD_FUNC_DECL(funcname) \
- DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, 0) \
- DEFUN_CMD_FUNC_TEXT(funcname)
+/* DEFUN variants */
#define DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \
DEFUN_CMD_FUNC_DECL(funcname) \
DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) \
DEFUN_CMD_FUNC_TEXT(funcname)
+#define DEFUN(funcname, cmdname, cmdstr, helpstr) \
+ DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, 0)
+
#define DEFUN_HIDDEN(funcname, cmdname, cmdstr, helpstr) \
DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN)
@@ -318,75 +317,55 @@ struct cmd_node {
/* DEFUN_NOSH for commands that vtysh should ignore */
#define DEFUN_NOSH(funcname, cmdname, cmdstr, helpstr) \
- DEFUN(funcname, cmdname, cmdstr, helpstr)
+ DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_NOSH)
#define DEFUN_YANG_NOSH(funcname, cmdname, cmdstr, helpstr) \
- DEFUN_YANG(funcname, cmdname, cmdstr, helpstr)
+ DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, \
+ CMD_ATTR_YANG | CMD_ATTR_NOSH)
/* DEFSH for vtysh. */
+#define DEFSH_ATTR(daemon, cmdname, cmdstr, helpstr, attr) \
+ DEFUN_CMD_ELEMENT(NULL, cmdname, cmdstr, helpstr, attr, daemon)
+
#define DEFSH(daemon, cmdname, cmdstr, helpstr) \
- DEFUN_CMD_ELEMENT(NULL, cmdname, cmdstr, helpstr, 0, daemon)
+ DEFSH_ATTR(daemon, cmdname, cmdstr, helpstr, 0)
#define DEFSH_HIDDEN(daemon, cmdname, cmdstr, helpstr) \
- DEFUN_CMD_ELEMENT(NULL, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN, \
- daemon)
-
-#define DEFSH_YANG(daemon, cmdname, cmdstr, helpstr) \
- DEFUN_CMD_ELEMENT(NULL, cmdname, cmdstr, helpstr, CMD_ATTR_YANG, daemon)
+ DEFSH_ATTR(daemon, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN)
/* DEFUN + DEFSH */
-#define DEFUNSH(daemon, funcname, cmdname, cmdstr, helpstr) \
- DEFUN_CMD_FUNC_DECL(funcname) \
- DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, daemon) \
- DEFUN_CMD_FUNC_TEXT(funcname)
-
-/* DEFUN + DEFSH with attributes */
#define DEFUNSH_ATTR(daemon, funcname, cmdname, cmdstr, helpstr, attr) \
DEFUN_CMD_FUNC_DECL(funcname) \
DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, daemon) \
DEFUN_CMD_FUNC_TEXT(funcname)
+#define DEFUNSH(daemon, funcname, cmdname, cmdstr, helpstr) \
+ DEFUNSH_ATTR(daemon, funcname, cmdname, cmdstr, helpstr, 0)
+
#define DEFUNSH_HIDDEN(daemon, funcname, cmdname, cmdstr, helpstr) \
DEFUNSH_ATTR(daemon, funcname, cmdname, cmdstr, helpstr, \
CMD_ATTR_HIDDEN)
-#define DEFUNSH_DEPRECATED(daemon, funcname, cmdname, cmdstr, helpstr) \
- DEFUNSH_ATTR(daemon, funcname, cmdname, cmdstr, helpstr, \
- CMD_ATTR_DEPRECATED)
-
-#define DEFUNSH_YANG(daemon, funcname, cmdname, cmdstr, helpstr) \
- DEFUNSH_ATTR(daemon, funcname, cmdname, cmdstr, helpstr, CMD_ATTR_YANG)
-
/* ALIAS macro which define existing command's alias. */
-#define ALIAS(funcname, cmdname, cmdstr, helpstr) \
- DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, 0)
-
#define ALIAS_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \
DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0)
+#define ALIAS(funcname, cmdname, cmdstr, helpstr) \
+ ALIAS_ATTR(funcname, cmdname, cmdstr, helpstr, 0)
+
#define ALIAS_HIDDEN(funcname, cmdname, cmdstr, helpstr) \
- DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN, \
- 0)
+ ALIAS_ATTR(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN)
+/* note: DEPRECATED implies HIDDEN, and other than that there is currently no
+ * difference. It's purely for expressing intent in the source code - a
+ * DEPRECATED command is supposed to go away, a HIDDEN one is likely to stay.
+ */
#define ALIAS_DEPRECATED(funcname, cmdname, cmdstr, helpstr) \
- DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, \
- CMD_ATTR_DEPRECATED, 0)
+ ALIAS_ATTR(funcname, cmdname, cmdstr, helpstr, \
+ CMD_ATTR_DEPRECATED | CMD_ATTR_HIDDEN)
#define ALIAS_YANG(funcname, cmdname, cmdstr, helpstr) \
- DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_YANG, 0)
-
-#define ALIAS_SH(daemon, funcname, cmdname, cmdstr, helpstr) \
- DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, 0, daemon)
-
-#define ALIAS_SH_HIDDEN(daemon, funcname, cmdname, cmdstr, helpstr) \
- DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_HIDDEN, \
- daemon)
-
-#define ALIAS_SH_DEPRECATED(daemon, funcname, cmdname, cmdstr, helpstr) \
- DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, \
- CMD_ATTR_DEPRECATED, daemon)
-
-#endif /* VTYSH_EXTRACT_PL */
+ ALIAS_ATTR(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_YANG)
/* Some macroes */
@@ -419,6 +398,7 @@ struct cmd_node {
#define BGP_SOFT_IN_STR "Send route-refresh unless using 'soft-reconfiguration inbound'\n"
#define BGP_SOFT_OUT_STR "Resend all outbound updates\n"
#define BGP_SOFT_RSCLIENT_RIB_STR "Soft reconfig for rsclient RIB\n"
+#define BGP_ORR_DEBUG "Enable Optimal Route Reflection Debugging logs\n"
#define OSPF_STR "OSPF information\n"
#define NEIGHBOR_STR "Specify neighbor router\n"
#define DEBUG_STR "Debugging functions\n"
@@ -528,7 +508,6 @@ struct xref_install_element {
enum node_type node_type;
};
-#ifndef VTYSH_EXTRACT_PL
#define install_element(node_type_, cmd_element_) do { \
static const struct xref_install_element _xref \
__attribute__((used)) = { \
@@ -540,7 +519,6 @@ struct xref_install_element {
XREF_LINK(_xref.xref); \
_install_element(node_type_, cmd_element_); \
} while (0)
-#endif
extern void _install_element(enum node_type, const struct cmd_element *);
@@ -651,6 +629,12 @@ extern char *cmd_variable_comp2str(vector comps, unsigned short cols);
extern void command_setup_early_logging(const char *dest, const char *level);
+/*
+ * Allow a mechanism for `debug XXX` commands that live
+ * under the lib directory to output their debug status
+ */
+extern void cmd_show_lib_debugs(struct vty *vty);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/command_graph.c b/lib/command_graph.c
index 09d802e79..e94068525 100644
--- a/lib/command_graph.c
+++ b/lib/command_graph.c
@@ -494,9 +494,10 @@ void cmd_graph_node_print_cb(struct graph_node *gn, struct buffer *buf)
snprintf(nbuf, sizeof(nbuf), "<b>%s</b>",
lookup_msg(tokennames, tok->type, NULL));
buffer_putstr(buf, nbuf);
- if (tok->attr == CMD_ATTR_DEPRECATED)
+ if (tok->attr & CMD_ATTR_DEPRECATED)
buffer_putstr(buf, " (d)");
- else if (tok->attr == CMD_ATTR_HIDDEN)
+ /* DEPRECATED implies HIDDEN, don't print both */
+ else if (tok->attr & CMD_ATTR_HIDDEN)
buffer_putstr(buf, " (h)");
if (tok->text) {
if (tok->type == WORD_TKN)
diff --git a/lib/command_graph.h b/lib/command_graph.h
index ed4da6aa4..b8c7a9c72 100644
--- a/lib/command_graph.h
+++ b/lib/command_graph.h
@@ -73,10 +73,11 @@ enum cmd_token_type {
#define IS_VARYING_TOKEN(x) ((x) >= VARIABLE_TKN && (x) < FORK_TKN)
/* Command attributes */
-enum { CMD_ATTR_NORMAL,
- CMD_ATTR_DEPRECATED,
- CMD_ATTR_HIDDEN,
- CMD_ATTR_YANG,
+enum {
+ CMD_ATTR_YANG = (1 << 0),
+ CMD_ATTR_HIDDEN = (1 << 1),
+ CMD_ATTR_DEPRECATED = (1 << 2),
+ CMD_ATTR_NOSH = (1 << 3),
};
enum varname_src {
diff --git a/lib/command_match.c b/lib/command_match.c
index f221e0a02..ce2dbc952 100644
--- a/lib/command_match.c
+++ b/lib/command_match.c
@@ -395,8 +395,7 @@ enum matcher_rv command_complete(struct graph *graph, vector vline,
for (ALL_LIST_ELEMENTS_RO(current, node, gstack)) {
struct cmd_token *token = gstack[0]->data;
- if (token->attr == CMD_ATTR_HIDDEN
- || token->attr == CMD_ATTR_DEPRECATED)
+ if (token->attr & CMD_ATTR_HIDDEN)
continue;
enum match_type minmatch = min_match_level(token->type);
diff --git a/lib/command_py.c b/lib/command_py.c
index 6301eec5e..cce9542e3 100644
--- a/lib/command_py.c
+++ b/lib/command_py.c
@@ -226,8 +226,8 @@ static PyObject *graph_to_pyobj(struct wrap_graph *wgraph,
wrap->type = "???";
}
- wrap->deprecated = (tok->attr == CMD_ATTR_DEPRECATED);
- wrap->hidden = (tok->attr == CMD_ATTR_HIDDEN);
+ wrap->deprecated = !!(tok->attr & CMD_ATTR_DEPRECATED);
+ wrap->hidden = !!(tok->attr & CMD_ATTR_HIDDEN);
wrap->text = tok->text;
wrap->desc = tok->desc;
wrap->varname = tok->varname;
@@ -353,6 +353,12 @@ PyMODINIT_FUNC command_py_init(void)
if (!pymod)
initret(NULL);
+ if (PyModule_AddIntMacro(pymod, CMD_ATTR_YANG)
+ || PyModule_AddIntMacro(pymod, CMD_ATTR_HIDDEN)
+ || PyModule_AddIntMacro(pymod, CMD_ATTR_DEPRECATED)
+ || PyModule_AddIntMacro(pymod, CMD_ATTR_NOSH))
+ initret(NULL);
+
Py_INCREF(&typeobj_graph_node);
PyModule_AddObject(pymod, "GraphNode", (PyObject *)&typeobj_graph_node);
Py_INCREF(&typeobj_graph);
diff --git a/lib/filter_cli.c b/lib/filter_cli.c
index 9a877a570..e0f0f177e 100644
--- a/lib/filter_cli.c
+++ b/lib/filter_cli.c
@@ -31,9 +31,7 @@
#include "lib/plist_int.h"
#include "lib/printfrr.h"
-#ifndef VTYSH_EXTRACT_PL
#include "lib/filter_cli_clippy.c"
-#endif /* VTYSH_EXTRACT_PL */
#define ACCESS_LIST_STR "Access list entry\n"
#define ACCESS_LIST_ZEBRA_STR "Access list name\n"
diff --git a/lib/frrscript.c b/lib/frrscript.c
index a19bd0c3d..2e5693261 100644
--- a/lib/frrscript.c
+++ b/lib/frrscript.c
@@ -184,13 +184,14 @@ static void *codec_alloc(void *arg)
return e;
}
-#if 0
-static void codec_free(struct codec *c)
+static void codec_free(void *data)
{
- XFREE(MTYPE_TMP, c->typename);
- XFREE(MTYPE_TMP, c);
+ struct frrscript_codec *c = data;
+ char *constworkaroundandihateit = (char *)c->typename;
+
+ XFREE(MTYPE_SCRIPT, constworkaroundandihateit);
+ XFREE(MTYPE_SCRIPT, c);
}
-#endif
/* Lua function hash utils */
@@ -212,17 +213,18 @@ bool lua_function_hash_cmp(const void *d1, const void *d2)
void *lua_function_alloc(void *arg)
{
struct lua_function_state *tmp = arg;
-
struct lua_function_state *lfs =
XCALLOC(MTYPE_SCRIPT, sizeof(struct lua_function_state));
+
lfs->name = tmp->name;
lfs->L = tmp->L;
return lfs;
}
-static void lua_function_free(struct hash_bucket *b, void *data)
+static void lua_function_free(void *data)
{
- struct lua_function_state *lfs = (struct lua_function_state *)b->data;
+ struct lua_function_state *lfs = data;
+
lua_close(lfs->L);
XFREE(MTYPE_SCRIPT, lfs);
}
@@ -409,7 +411,8 @@ fail:
void frrscript_delete(struct frrscript *fs)
{
- hash_iterate(fs->lua_function_hash, lua_function_free, NULL);
+ hash_clean(fs->lua_function_hash, lua_function_free);
+ hash_free(fs->lua_function_hash);
XFREE(MTYPE_SCRIPT, fs->name);
XFREE(MTYPE_SCRIPT, fs);
}
@@ -425,4 +428,11 @@ void frrscript_init(const char *sd)
frrscript_register_type_codecs(frrscript_codecs_lib);
}
+void frrscript_fini(void)
+{
+ hash_clean(codec_hash, codec_free);
+ hash_free(codec_hash);
+
+ frrscript_names_destroy();
+}
#endif /* HAVE_SCRIPTING */
diff --git a/lib/frrscript.h b/lib/frrscript.h
index 4db3e6f1b..7fa01f70d 100644
--- a/lib/frrscript.h
+++ b/lib/frrscript.h
@@ -162,6 +162,11 @@ void frrscript_register_type_codecs(struct frrscript_codec *codecs);
void frrscript_init(const char *scriptdir);
/*
+ * On shutdown clean up memory associated with the scripting subsystem
+ */
+void frrscript_fini(void);
+
+/*
* This macro is mapped to every (name, value) in frrscript_call,
* so this in turn maps them onto their encoders
*/
diff --git a/lib/frrstr.c b/lib/frrstr.c
index 1b98b224c..d66c6f8c1 100644
--- a/lib/frrstr.c
+++ b/lib/frrstr.c
@@ -23,11 +23,16 @@
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
-#ifdef HAVE_LIBPCREPOSIX
+#ifdef HAVE_LIBPCRE2_POSIX
+#ifndef _FRR_PCRE2_POSIX
+#define _FRR_PCRE2_POSIX
+#include <pcre2posix.h>
+#endif /* _FRR_PCRE2_POSIX */
+#elif defined(HAVE_LIBPCREPOSIX)
#include <pcreposix.h>
#else
#include <regex.h>
-#endif /* HAVE_LIBPCREPOSIX */
+#endif /* HAVE_LIBPCRE2_POSIX */
#include "frrstr.h"
#include "memory.h"
diff --git a/lib/frrstr.h b/lib/frrstr.h
index d52d6a448..f0066d0fc 100644
--- a/lib/frrstr.h
+++ b/lib/frrstr.h
@@ -23,11 +23,16 @@
#include <sys/types.h>
#include <sys/types.h>
-#ifdef HAVE_LIBPCREPOSIX
+#ifdef HAVE_LIBPCRE2_POSIX
+#ifndef _FRR_PCRE2_POSIX
+#define _FRR_PCRE2_POSIX
+#include <pcre2posix.h>
+#endif /* _FRR_PCRE2_POSIX */
+#elif defined(HAVE_LIBPCREPOSIX)
#include <pcreposix.h>
#else
#include <regex.h>
-#endif /* HAVE_LIBPCREPOSIX */
+#endif /* HAVE_LIBPCRE2_POSIX */
#include <stdbool.h>
#include "vector.h"
diff --git a/lib/grammar_sandbox.c b/lib/grammar_sandbox.c
index f9778c5d4..8fa47c053 100644
--- a/lib/grammar_sandbox.c
+++ b/lib/grammar_sandbox.c
@@ -76,8 +76,7 @@ DEFUN (grammar_test,
// parse the command and install it into the command graph
struct graph *graph = graph_new();
- struct cmd_token *token =
- cmd_token_new(START_TKN, CMD_ATTR_NORMAL, NULL, NULL);
+ struct cmd_token *token = cmd_token_new(START_TKN, 0, NULL, NULL);
graph_new_node(graph, token, (void (*)(void *)) & cmd_token_del);
cmd_graph_parse(graph, cmd);
diff --git a/lib/if.c b/lib/if.c
index fa4fdb82d..76568071e 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -35,9 +35,7 @@
#include "buffer.h"
#include "log.h"
#include "northbound_cli.h"
-#ifndef VTYSH_EXTRACT_PL
#include "lib/if_clippy.c"
-#endif
DEFINE_MTYPE_STATIC(LIB, IF, "Interface");
DEFINE_MTYPE_STATIC(LIB, CONNECTED, "Connected");
@@ -1095,13 +1093,15 @@ const char *if_link_type_str(enum zebra_link_type llt)
struct if_link_params *if_link_params_get(struct interface *ifp)
{
- int i;
+ return ifp->link_params;
+}
- if (ifp->link_params != NULL)
- return ifp->link_params;
+struct if_link_params *if_link_params_enable(struct interface *ifp)
+{
+ struct if_link_params *iflp;
+ int i;
- struct if_link_params *iflp =
- XCALLOC(MTYPE_IF_LINK_PARAMS, sizeof(struct if_link_params));
+ iflp = if_link_params_init(ifp);
/* Compute default bandwidth based on interface */
iflp->default_bw =
@@ -1129,6 +1129,20 @@ struct if_link_params *if_link_params_get(struct interface *ifp)
return iflp;
}
+struct if_link_params *if_link_params_init(struct interface *ifp)
+{
+ struct if_link_params *iflp = if_link_params_get(ifp);
+
+ if (iflp)
+ return iflp;
+
+ iflp = XCALLOC(MTYPE_IF_LINK_PARAMS, sizeof(struct if_link_params));
+
+ ifp->link_params = iflp;
+
+ return iflp;
+}
+
void if_link_params_free(struct interface *ifp)
{
XFREE(MTYPE_IF_LINK_PARAMS, ifp->link_params);
diff --git a/lib/if.h b/lib/if.h
index 1c948b875..91dcd4624 100644
--- a/lib/if.h
+++ b/lib/if.h
@@ -143,9 +143,13 @@ struct if_stats {
#define TE_EXT_MASK 0x0FFFFFFF
#define TE_EXT_ANORMAL 0x80000000
#define LOSS_PRECISION 0.000003
+/* TE_MEGA_BIT and TE_BYTE are utilized to convert TE bandwidth */
#define TE_MEGA_BIT 1000000
#define TE_BYTE 8
-#define DEFAULT_BANDWIDTH 10000
+/* Default TE bandwidth when no value in config.
+ * The value is in Mbps (will be multiplied by TE_BYTE)
+ */
+#define DEFAULT_BANDWIDTH 10
#define MAX_CLASS_TYPE 8
#define MAX_PKT_LOSS 50.331642
@@ -588,6 +592,8 @@ struct connected *connected_get_linklocal(struct interface *ifp);
/* link parameters */
struct if_link_params *if_link_params_get(struct interface *);
+struct if_link_params *if_link_params_enable(struct interface *ifp);
+struct if_link_params *if_link_params_init(struct interface *ifp);
void if_link_params_free(struct interface *);
/* Northbound. */
diff --git a/lib/ipaddr.h b/lib/ipaddr.h
index d7ab358af..43b302820 100644
--- a/lib/ipaddr.h
+++ b/lib/ipaddr.h
@@ -61,6 +61,8 @@ struct ipaddr {
#define IPADDRSZ(p) \
(IS_IPADDR_V4((p)) ? sizeof(struct in_addr) : sizeof(struct in6_addr))
+#define IPADDR_STRING_SIZE 46
+
static inline int ipaddr_family(const struct ipaddr *ip)
{
switch (ip->ipa_type) {
diff --git a/lib/libfrr.c b/lib/libfrr.c
index f5aecd9f7..aee698185 100644
--- a/lib/libfrr.c
+++ b/lib/libfrr.c
@@ -1219,6 +1219,10 @@ void frr_fini(void)
db_close();
#endif
log_ref_fini();
+
+#ifdef HAVE_SCRIPTING
+ frrscript_fini();
+#endif
frr_pthread_finish();
zprivs_terminate(di->privs);
/* signal_init -> nothing needed */
diff --git a/lib/linklist.c b/lib/linklist.c
index 851948288..d1b57084e 100644
--- a/lib/linklist.c
+++ b/lib/linklist.c
@@ -98,9 +98,10 @@ void listnode_add_head(struct list *list, void *val)
node->next = list->head;
- if (list->head == NULL)
+ if (list->head == NULL) {
list->head = node;
- else
+ list->tail = node;
+ } else
list->head->prev = node;
list->head = node;
diff --git a/lib/log_vty.c b/lib/log_vty.c
index 81280f302..4091c92c7 100644
--- a/lib/log_vty.c
+++ b/lib/log_vty.c
@@ -29,9 +29,7 @@
#include "lib/printfrr.h"
#include "lib/systemd.h"
-#ifndef VTYSH_EXTRACT_PL
#include "lib/log_vty_clippy.c"
-#endif
#define ZLOG_MAXLVL(a, b) MAX(a, b)
@@ -761,8 +759,8 @@ DEFPY (log_immediate_mode,
log_immediate_mode_cmd,
"[no] log immediate-mode",
NO_STR
- "Logging control"
- "Output immediately, without buffering")
+ "Logging control\n"
+ "Output immediately, without buffering\n")
{
zlog_set_immediate(!no);
return CMD_SUCCESS;
diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c
index 7284d6cea..41fe64606 100644
--- a/lib/nexthop_group.c
+++ b/lib/nexthop_group.c
@@ -28,9 +28,7 @@
#include <command.h>
#include <jhash.h>
-#ifndef VTYSH_EXTRACT_PL
#include "lib/nexthop_group_clippy.c"
-#endif
DEFINE_MTYPE_STATIC(LIB, NEXTHOP_GROUP, "Nexthop Group");
@@ -49,6 +47,7 @@ struct nexthop_hold {
struct nexthop_group_hooks {
void (*new)(const char *name);
+ void (*modify)(const struct nexthop_group_cmd *nhgc);
void (*add_nexthop)(const struct nexthop_group_cmd *nhg,
const struct nexthop *nhop);
void (*del_nexthop)(const struct nexthop_group_cmd *nhg,
@@ -274,6 +273,7 @@ struct nexthop_group *nexthop_group_new(void)
void nexthop_group_copy(struct nexthop_group *to,
const struct nexthop_group *from)
{
+ to->nhgr = from->nhgr;
/* Copy everything, including recursive info */
copy_nexthops(&to->nexthop, from->nexthop, NULL);
}
@@ -675,6 +675,50 @@ DEFPY(no_nexthop_group_backup, no_nexthop_group_backup_cmd,
return CMD_SUCCESS;
}
+DEFPY(nexthop_group_resilience,
+ nexthop_group_resilience_cmd,
+ "resilient buckets (1-256) idle-timer (1-4294967295) unbalanced-timer (1-4294967295)",
+ "A resilient Nexthop Group\n"
+ "Buckets in the Hash for this Group\n"
+ "Number of buckets\n"
+ "The Idle timer for this Resilient Nexthop Group in seconds\n"
+ "Number of seconds of Idle time\n"
+ "The length of time that the Nexthop Group can be unbalanced\n"
+ "Number of seconds of Unbalanced time\n")
+{
+ VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc);
+
+ nhgc->nhg.nhgr.buckets = buckets;
+ nhgc->nhg.nhgr.idle_timer = idle_timer;
+ nhgc->nhg.nhgr.unbalanced_timer = unbalanced_timer;
+
+ if (nhg_hooks.modify)
+ nhg_hooks.modify(nhgc);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY(no_nexthop_group_resilience,
+ no_nexthop_group_resilience_cmd,
+ "no resilient [buckets (1-256) idle-timer (1-4294967295) unbalanced-timer (1-4294967295)]",
+ NO_STR
+ "A resilient Nexthop Group\n"
+ "Buckets in the Hash for this Group\n"
+ "Number of buckets\n"
+ "The Idle timer for this Resilient Nexthop Group in seconds\n"
+ "Number of seconds of Idle time\n"
+ "The length of time that the Nexthop Group can be unbalanced\n"
+ "Number of seconds of Unbalanced time\n")
+{
+ VTY_DECLVAR_CONTEXT(nexthop_group_cmd, nhgc);
+
+ nhgc->nhg.nhgr.buckets = 0;
+ nhgc->nhg.nhgr.idle_timer = 0;
+ nhgc->nhg.nhgr.unbalanced_timer = 0;
+
+ return CMD_SUCCESS;
+}
+
static void nexthop_group_save_nhop(struct nexthop_group_cmd *nhgc,
const char *nhvrf_name,
const union sockunion *addr,
@@ -1130,6 +1174,13 @@ static int nexthop_group_write(struct vty *vty)
vty_out(vty, "nexthop-group %s\n", nhgc->name);
+ if (nhgc->nhg.nhgr.buckets)
+ vty_out(vty,
+ " resilient buckets %u idle-timer %u unbalanced-timer %u\n",
+ nhgc->nhg.nhgr.buckets,
+ nhgc->nhg.nhgr.idle_timer,
+ nhgc->nhg.nhgr.unbalanced_timer);
+
if (nhgc->backup_list_name[0])
vty_out(vty, " backup-group %s\n",
nhgc->backup_list_name);
@@ -1300,6 +1351,7 @@ static const struct cmd_variable_handler nhg_name_handlers[] = {
{.completions = NULL}};
void nexthop_group_init(void (*new)(const char *name),
+ void (*modify)(const struct nexthop_group_cmd *nhgc),
void (*add_nexthop)(const struct nexthop_group_cmd *nhg,
const struct nexthop *nhop),
void (*del_nexthop)(const struct nexthop_group_cmd *nhg,
@@ -1319,10 +1371,15 @@ void nexthop_group_init(void (*new)(const char *name),
install_element(NH_GROUP_NODE, &no_nexthop_group_backup_cmd);
install_element(NH_GROUP_NODE, &ecmp_nexthops_cmd);
+ install_element(NH_GROUP_NODE, &nexthop_group_resilience_cmd);
+ install_element(NH_GROUP_NODE, &no_nexthop_group_resilience_cmd);
+
memset(&nhg_hooks, 0, sizeof(nhg_hooks));
if (new)
nhg_hooks.new = new;
+ if (modify)
+ nhg_hooks.modify = modify;
if (add_nexthop)
nhg_hooks.add_nexthop = add_nexthop;
if (del_nexthop)
diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h
index 8e75e5c6a..0ea0b7c18 100644
--- a/lib/nexthop_group.h
+++ b/lib/nexthop_group.h
@@ -28,6 +28,13 @@
extern "C" {
#endif
+struct nhg_resilience {
+ uint16_t buckets;
+ uint32_t idle_timer;
+ uint32_t unbalanced_timer;
+ uint64_t unbalanced_time;
+};
+
/*
* What is a nexthop group?
*
@@ -38,6 +45,8 @@ extern "C" {
*/
struct nexthop_group {
struct nexthop *nexthop;
+
+ struct nhg_resilience nhgr;
};
struct nexthop_group *nexthop_group_new(void);
@@ -109,9 +118,17 @@ DECLARE_QOBJ_TYPE(nexthop_group_cmd);
* a nexthop_group is added/deleted/modified, then set the
* appropriate callback functions to handle it in your
* code
+ *
+ * create - The creation of the nexthop group
+ * modify - Modification of the nexthop group when not changing a nexthop
+ * ( resilience as an example )
+ * add_nexthop - A nexthop is added to the NHG
+ * del_nexthop - A nexthop is deleted from the NHG
+ * destroy - The NHG is deleted
*/
void nexthop_group_init(
void (*create)(const char *name),
+ void (*modify)(const struct nexthop_group_cmd *nhgc),
void (*add_nexthop)(const struct nexthop_group_cmd *nhgc,
const struct nexthop *nhop),
void (*del_nexthop)(const struct nexthop_group_cmd *nhgc,
diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c
index 56eac9dc3..e0dcdb490 100644
--- a/lib/northbound_cli.c
+++ b/lib/northbound_cli.c
@@ -32,9 +32,7 @@
#include "northbound.h"
#include "northbound_cli.h"
#include "northbound_db.h"
-#ifndef VTYSH_EXTRACT_PL
#include "lib/northbound_cli_clippy.c"
-#endif
struct debug nb_dbg_cbs_config = {0, "Northbound callbacks: configuration"};
struct debug nb_dbg_cbs_state = {0, "Northbound callbacks: state"};
diff --git a/lib/orr_msg.h b/lib/orr_msg.h
new file mode 100644
index 000000000..b0c4c48df
--- /dev/null
+++ b/lib/orr_msg.h
@@ -0,0 +1,94 @@
+/*
+ * Structures common to BGP, OSPF and ISIS for BGP Optimal Route Reflection
+ * Copyright (C) 2021 Samsung R&D Institute India - Bangalore.
+ * Madhurilatha Kuruganti
+ *
+ * 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_ORR_MSG_H
+#define _FRR_ORR_MSG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* REVISIT: Need to check if we can use zero length array */
+#define ORR_MAX_PREFIX 100
+#define ORR_GROUP_NAME_SIZE 32
+
+struct orr_prefix_metric {
+ struct prefix prefix;
+ uint32_t metric;
+};
+
+/* BGP-IGP Register for IGP metric */
+struct orr_igp_metric_reg {
+ bool reg;
+ uint8_t proto;
+ safi_t safi;
+ struct prefix prefix;
+ char group_name[ORR_GROUP_NAME_SIZE];
+};
+
+/* IGP-BGP message structures */
+struct orr_igp_metric_info {
+ /* IGP instance data. */
+ uint8_t proto;
+ uint32_t instId;
+
+ safi_t safi;
+
+ /* Add or delete routes */
+ bool add;
+
+ /* IGP metric from Active Root. */
+ struct prefix root;
+ uint32_t num_entries;
+ struct orr_prefix_metric nexthop[ORR_MAX_PREFIX];
+};
+
+/* BGP ORR Root node */
+struct orr_root {
+ afi_t afi;
+ safi_t safi;
+
+ char group_name[ORR_GROUP_NAME_SIZE];
+
+ /* MPLS_TE prefix and router ID */
+ struct prefix prefix;
+ struct in_addr router_id;
+
+ /* Advertising OSPF Router ID. */
+ struct in_addr adv_router;
+
+ /* BGP-ORR Received LSAs */
+ struct ospf_lsa *router_lsa_rcvd;
+
+ /* Routing tables from root node */
+ struct route_table *old_table; /* Old routing table. */
+ struct route_table *new_table; /* Current routing table. */
+
+ struct route_table *old_rtrs; /* Old ABR/ASBR RT. */
+ struct route_table *new_rtrs; /* New ABR/ASBR RT. */
+};
+
+/* Prototypes. */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _FRR_ORR_MSG_H */
diff --git a/lib/plist.c b/lib/plist.c
index ff2a59ba2..17e692d13 100644
--- a/lib/plist.c
+++ b/lib/plist.c
@@ -1193,9 +1193,7 @@ static int vty_clear_prefix_list(struct vty *vty, afi_t afi, const char *name,
return CMD_SUCCESS;
}
-#ifndef VTYSH_EXTRACT_PL
#include "lib/plist_clippy.c"
-#endif
DEFPY (show_ip_prefix_list,
show_ip_prefix_list_cmd,
diff --git a/lib/prefix.c b/lib/prefix.c
index e64b10bf2..4642f14d3 100644
--- a/lib/prefix.c
+++ b/lib/prefix.c
@@ -1404,6 +1404,63 @@ bool ipv4_unicast_valid(const struct in_addr *addr)
return true;
}
+static int ipaddr2prefix(const struct ipaddr *ip, uint16_t prefixlen,
+ struct prefix *p)
+{
+ switch (ip->ipa_type) {
+ case (IPADDR_V4):
+ p->family = AF_INET;
+ p->u.prefix4 = ip->ipaddr_v4;
+ p->prefixlen = prefixlen;
+ break;
+ case (IPADDR_V6):
+ p->family = AF_INET6;
+ p->u.prefix6 = ip->ipaddr_v6;
+ p->prefixlen = prefixlen;
+ break;
+ case (IPADDR_NONE):
+ p->family = AF_UNSPEC;
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * Convert type-2 and type-5 evpn route prefixes into the more
+ * general ipv4/ipv6 prefix types so we can match prefix lists
+ * and such.
+ */
+int evpn_prefix2prefix(const struct prefix *evpn, struct prefix *to)
+{
+ const struct evpn_addr *addr;
+
+ if (evpn->family != AF_EVPN)
+ return -1;
+
+ addr = &evpn->u.prefix_evpn;
+
+ switch (addr->route_type) {
+ case BGP_EVPN_MAC_IP_ROUTE:
+ if (IS_IPADDR_V4(&addr->macip_addr.ip))
+ ipaddr2prefix(&addr->macip_addr.ip, 32, to);
+ else if (IS_IPADDR_V6(&addr->macip_addr.ip))
+ ipaddr2prefix(&addr->macip_addr.ip, 128, to);
+ else
+ return -1; /* mac only? */
+
+ break;
+ case BGP_EVPN_IP_PREFIX_ROUTE:
+ ipaddr2prefix(&addr->prefix_addr.ip,
+ addr->prefix_addr.ip_prefix_length, to);
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
printfrr_ext_autoreg_p("EA", printfrr_ea);
static ssize_t printfrr_ea(struct fbuf *buf, struct printfrr_eargs *ea,
const void *ptr)
diff --git a/lib/prefix.h b/lib/prefix.h
index b90431153..c67656cfd 100644
--- a/lib/prefix.h
+++ b/lib/prefix.h
@@ -510,6 +510,7 @@ extern char *esi_to_str(const esi_t *esi, char *buf, int size);
extern char *evpn_es_df_alg2str(uint8_t df_alg, char *buf, int buf_len);
extern void prefix_evpn_hexdump(const struct prefix_evpn *p);
extern bool ipv4_unicast_valid(const struct in_addr *addr);
+extern int evpn_prefix2prefix(const struct prefix *evpn, struct prefix *to);
static inline int ipv6_martian(const struct in6_addr *addr)
{
diff --git a/lib/routemap.c b/lib/routemap.c
index 3cc010c14..44d718556 100644
--- a/lib/routemap.c
+++ b/lib/routemap.c
@@ -1815,7 +1815,24 @@ route_map_get_index(struct route_map *map, const struct prefix *prefix,
struct route_map_index *index = NULL, *best_index = NULL;
struct route_map_index *head_index = NULL;
struct route_table *table = NULL;
- unsigned char family = prefix->family;
+ struct prefix conv;
+ unsigned char family;
+
+ /*
+ * Handling for matching evpn_routes in the prefix table.
+ *
+ * We convert type2/5 prefix to ipv4/6 prefix to do longest
+ * prefix matching on.
+ */
+ if (prefix->family == AF_EVPN) {
+ if (evpn_prefix2prefix(prefix, &conv) != 0)
+ return NULL;
+
+ prefix = &conv;
+ }
+
+
+ family = prefix->family;
if (family == AF_INET)
table = map->ipv4_prefix_table;
@@ -1890,12 +1907,7 @@ route_map_get_index(struct route_map *map, const struct prefix *prefix,
static int route_map_candidate_list_cmp(struct route_map_index *idx1,
struct route_map_index *idx2)
{
- if (!idx1)
- return -1;
- if (!idx2)
- return 1;
-
- return (idx1->pref - idx2->pref);
+ return idx1->pref - idx2->pref;
}
/*
@@ -3174,6 +3186,12 @@ static struct cmd_node rmap_debug_node = {
.config_write = rmap_config_write_debug,
};
+void route_map_show_debug(struct vty *vty)
+{
+ if (rmap_debug)
+ vty_out(vty, "debug route-map\n");
+}
+
/* Configuration write function. */
static int rmap_config_write_debug(struct vty *vty)
{
diff --git a/lib/routemap.h b/lib/routemap.h
index a36592585..9c78e1573 100644
--- a/lib/routemap.h
+++ b/lib/routemap.h
@@ -348,6 +348,7 @@ DECLARE_QOBJ_TYPE(route_map);
(strmatch(A, "frr-bgp-route-map:set-origin"))
#define IS_SET_ATOMIC_AGGREGATE(A) \
(strmatch(A, "frr-bgp-route-map:atomic-aggregate"))
+#define IS_SET_AIGP_METRIC(A) (strmatch(A, "frr-bgp-route-map:aigp-metric"))
#define IS_SET_ORIGINATOR_ID(A) \
(strmatch(A, "frr-bgp-route-map:originator-id"))
#define IS_SET_COMM_LIST_DEL(A) \
@@ -1015,6 +1016,8 @@ extern void route_map_optimization_disabled_show(struct vty *vty,
bool show_defaults);
extern void route_map_cli_init(void);
+extern void route_map_show_debug(struct vty *vty);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c
index 6be5d15ec..cedee83d8 100644
--- a/lib/routemap_cli.c
+++ b/lib/routemap_cli.c
@@ -26,9 +26,7 @@
#include "lib/northbound_cli.h"
#include "lib/routemap.h"
-#ifndef VTYSH_EXTRACT_PL
#include "lib/routemap_cli_clippy.c"
-#endif /* VTYSH_EXTRACT_PL */
#define ROUTE_MAP_CMD_STR \
"Create route-map or enter route-map command mode\n" \
@@ -1089,6 +1087,11 @@ void route_map_action_show(struct vty *vty, const struct lyd_node *dnode,
"./rmap-set-action/frr-bgp-route-map:origin"));
} else if (IS_SET_ATOMIC_AGGREGATE(action)) {
vty_out(vty, " set atomic-aggregate\n");
+ } else if (IS_SET_AIGP_METRIC(action)) {
+ vty_out(vty, " set aigp-metric %s\n",
+ yang_dnode_get_string(
+ dnode,
+ "./rmap-set-action/frr-bgp-route-map:aigp-metric"));
} else if (IS_SET_ORIGINATOR_ID(action)) {
vty_out(vty, " set originator-id %s\n",
yang_dnode_get_string(
diff --git a/lib/sockopt.c b/lib/sockopt.c
index 7a2b8a1c8..de11a9eab 100644
--- a/lib/sockopt.c
+++ b/lib/sockopt.c
@@ -693,3 +693,52 @@ int sockopt_tcp_mss_get(int sock)
return tcp_maxseg;
}
+
+int setsockopt_tcp_keepalive(int sock, uint16_t keepalive_idle,
+ uint16_t keepalive_intvl,
+ uint16_t keepalive_probes)
+{
+ int val = 1;
+
+ if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) < 0) {
+ flog_err_sys(EC_LIB_SYSTEM_CALL,
+ "%s failed: setsockopt SO_KEEPALIVE (%d): %s",
+ __func__, sock, safe_strerror(errno));
+ return -1;
+ }
+
+#if defined __OpenBSD__
+ return 0;
+#else
+ /* Send first probe after keepalive_idle seconds */
+ val = keepalive_idle;
+ if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof(val)) <
+ 0) {
+ flog_err_sys(EC_LIB_SYSTEM_CALL,
+ "%s failed: setsockopt TCP_KEEPIDLE (%d): %s",
+ __func__, sock, safe_strerror(errno));
+ return -1;
+ }
+
+ /* Set interval between two probes */
+ val = keepalive_intvl;
+ if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &val, sizeof(val)) <
+ 0) {
+ flog_err_sys(EC_LIB_SYSTEM_CALL,
+ "%s failed: setsockopt TCP_KEEPINTVL (%d): %s",
+ __func__, sock, safe_strerror(errno));
+ return -1;
+ }
+
+ /* Set maximum probes */
+ val = keepalive_probes;
+ if (setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &val, sizeof(val)) < 0) {
+ flog_err_sys(EC_LIB_SYSTEM_CALL,
+ "%s failed: setsockopt TCP_KEEPCNT (%d): %s",
+ __func__, sock, safe_strerror(errno));
+ return -1;
+ }
+
+ return 0;
+#endif
+}
diff --git a/lib/sockopt.h b/lib/sockopt.h
index 6c80841e3..694edf763 100644
--- a/lib/sockopt.h
+++ b/lib/sockopt.h
@@ -153,6 +153,28 @@ extern int sockopt_tcp_mss_set(int sock, int tcp_maxseg);
* Socket to get max segement size.
*/
extern int sockopt_tcp_mss_get(int sock);
+
+/*
+ * Configure TCP keepalive for a given socket
+ *
+ * sock
+ * Socket to enable keepalive option on.
+ *
+ * keepalive_idle
+ * number of seconds a connection needs to be idle
+ * before sending out keep-alive proves
+ *
+ * keepalive_intvl
+ * number of seconds between TCP keep-alive probes
+ *
+ * keepalive_probes
+ * max number of probers to send before giving up
+ * and killing tcp connection
+ */
+extern int setsockopt_tcp_keepalive(int sock, uint16_t keepalive_idle,
+ uint16_t keepalive_intvl,
+ uint16_t keepalive_probes);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/srv6.c b/lib/srv6.c
index 6a658444c..5cd82080f 100644
--- a/lib/srv6.c
+++ b/lib/srv6.c
@@ -57,6 +57,8 @@ const char *seg6local_action2str(uint32_t action)
return "End.AS";
case ZEBRA_SEG6_LOCAL_ACTION_END_AM:
return "End.AM";
+ case ZEBRA_SEG6_LOCAL_ACTION_END_DT46:
+ return "End.DT46";
case ZEBRA_SEG6_LOCAL_ACTION_UNSPEC:
return "unspec";
default:
@@ -83,8 +85,6 @@ const char *seg6local_context2str(char *str, size_t size,
const struct seg6local_context *ctx,
uint32_t action)
{
- char b0[128];
-
switch (action) {
case ZEBRA_SEG6_LOCAL_ACTION_END:
@@ -93,18 +93,17 @@ const char *seg6local_context2str(char *str, size_t size,
case ZEBRA_SEG6_LOCAL_ACTION_END_X:
case ZEBRA_SEG6_LOCAL_ACTION_END_DX6:
- inet_ntop(AF_INET6, &ctx->nh6, b0, 128);
- snprintf(str, size, "nh6 %s", b0);
+ snprintfrr(str, size, "nh6 %pI6", &ctx->nh6);
return str;
case ZEBRA_SEG6_LOCAL_ACTION_END_DX4:
- inet_ntop(AF_INET, &ctx->nh4, b0, 128);
- snprintf(str, size, "nh4 %s", b0);
+ snprintfrr(str, size, "nh4 %pI4", &ctx->nh4);
return str;
case ZEBRA_SEG6_LOCAL_ACTION_END_T:
case ZEBRA_SEG6_LOCAL_ACTION_END_DT6:
case ZEBRA_SEG6_LOCAL_ACTION_END_DT4:
+ case ZEBRA_SEG6_LOCAL_ACTION_END_DT46:
snprintf(str, size, "table %u", ctx->table);
return str;
@@ -154,9 +153,9 @@ void srv6_locator_free(struct srv6_locator *locator)
}
}
-void srv6_locator_chunk_free(struct srv6_locator_chunk *chunk)
+void srv6_locator_chunk_free(struct srv6_locator_chunk **chunk)
{
- XFREE(MTYPE_SRV6_LOCATOR_CHUNK, chunk);
+ XFREE(MTYPE_SRV6_LOCATOR_CHUNK, *chunk);
}
json_object *srv6_locator_chunk_json(const struct srv6_locator_chunk *chunk)
@@ -228,10 +227,24 @@ json_object *srv6_locator_json(const struct srv6_locator *loc)
/* set prefix */
json_object_string_addf(jo_root, "prefix", "%pFX", &loc->prefix);
+ /* set block_bits_length */
+ json_object_int_add(jo_root, "blockBitsLength", loc->block_bits_length);
+
+ /* set node_bits_length */
+ json_object_int_add(jo_root, "nodeBitsLength", loc->node_bits_length);
+
/* set function_bits_length */
json_object_int_add(jo_root, "functionBitsLength",
loc->function_bits_length);
+ /* set argument_bits_length */
+ json_object_int_add(jo_root, "argumentBitsLength",
+ loc->argument_bits_length);
+
+ /* set true if the locator is a Micro-segment (uSID) locator */
+ if (CHECK_FLAG(loc->flags, SRV6_LOCATOR_USID))
+ json_object_string_add(jo_root, "behavior", "usid");
+
/* set status_up */
json_object_boolean_add(jo_root, "statusUp",
loc->status_up);
@@ -277,6 +290,10 @@ json_object *srv6_locator_detailed_json(const struct srv6_locator *loc)
json_object_int_add(jo_root, "argumentBitsLength",
loc->argument_bits_length);
+ /* set true if the locator is a Micro-segment (uSID) locator */
+ if (CHECK_FLAG(loc->flags, SRV6_LOCATOR_USID))
+ json_object_string_add(jo_root, "behavior", "usid");
+
/* set algonum */
json_object_int_add(jo_root, "algoNum", loc->algonum);
diff --git a/lib/srv6.h b/lib/srv6.h
index e0db30cd1..acfb0631c 100644
--- a/lib/srv6.h
+++ b/lib/srv6.h
@@ -60,6 +60,7 @@ enum seg6local_action_t {
ZEBRA_SEG6_LOCAL_ACTION_END_AS = 13,
ZEBRA_SEG6_LOCAL_ACTION_END_AM = 14,
ZEBRA_SEG6_LOCAL_ACTION_END_BPF = 15,
+ ZEBRA_SEG6_LOCAL_ACTION_END_DT46 = 16,
};
struct seg6_segs {
@@ -91,6 +92,9 @@ struct srv6_locator {
bool status_up;
struct list *chunks;
+ uint8_t flags;
+#define SRV6_LOCATOR_USID (1 << 0) /* The SRv6 Locator is a uSID Locator */
+
QOBJ_FIELDS;
};
DECLARE_QOBJ_TYPE(srv6_locator);
@@ -115,6 +119,23 @@ struct srv6_locator_chunk {
uint8_t proto;
uint16_t instance;
uint32_t session_id;
+
+ uint8_t flags;
+};
+
+/*
+ * SRv6 Endpoint Behavior codepoints, as defined by IANA in
+ * https://www.iana.org/assignments/segment-routing/segment-routing.xhtml
+ */
+enum srv6_endpoint_behavior_codepoint {
+ SRV6_ENDPOINT_BEHAVIOR_RESERVED = 0x0000,
+ SRV6_ENDPOINT_BEHAVIOR_END_DT6 = 0x0012,
+ SRV6_ENDPOINT_BEHAVIOR_END_DT4 = 0x0013,
+ SRV6_ENDPOINT_BEHAVIOR_END_DT46 = 0x0014,
+ SRV6_ENDPOINT_BEHAVIOR_END_DT6_USID = 0x003E,
+ SRV6_ENDPOINT_BEHAVIOR_END_DT4_USID = 0x003F,
+ SRV6_ENDPOINT_BEHAVIOR_END_DT46_USID = 0x0040,
+ SRV6_ENDPOINT_BEHAVIOR_OPAQUE = 0xFFFF,
};
struct nexthop_srv6 {
@@ -186,7 +207,7 @@ int snprintf_seg6_segs(char *str,
extern struct srv6_locator *srv6_locator_alloc(const char *name);
extern struct srv6_locator_chunk *srv6_locator_chunk_alloc(void);
extern void srv6_locator_free(struct srv6_locator *locator);
-extern void srv6_locator_chunk_free(struct srv6_locator_chunk *chunk);
+extern void srv6_locator_chunk_free(struct srv6_locator_chunk **chunk);
json_object *srv6_locator_chunk_json(const struct srv6_locator_chunk *chunk);
json_object *srv6_locator_json(const struct srv6_locator *loc);
json_object *srv6_locator_detailed_json(const struct srv6_locator *loc);
diff --git a/lib/stream.h b/lib/stream.h
index 35733e743..a3c148c9c 100644
--- a/lib/stream.h
+++ b/lib/stream.h
@@ -386,6 +386,18 @@ extern void stream_fifo_free(struct stream_fifo *fifo);
* bit), for 64-bit values (you need to cast them anyway), and neither for
* encoding (because it's downcasted.)
*/
+static inline const uint8_t *ptr_get_be64(const uint8_t *ptr, uint64_t *out)
+{
+ uint32_t tmp1, tmp2;
+
+ memcpy(&tmp1, ptr, sizeof(tmp1));
+ memcpy(&tmp2, ptr + sizeof(tmp1), sizeof(tmp1));
+
+ *out = (((uint64_t)ntohl(tmp1)) << 32) | ntohl(tmp2);
+
+ return ptr + 8;
+}
+
static inline const uint8_t *ptr_get_be32(const uint8_t *ptr, uint32_t *out)
{
uint32_t tmp;
diff --git a/lib/subdir.am b/lib/subdir.am
index d6defd714..ea6cb9339 100644
--- a/lib/subdir.am
+++ b/lib/subdir.am
@@ -139,27 +139,6 @@ nodist_lib_libfrr_la_SOURCES = \
yang/frr-module-translator.yang.c \
# end
-vtysh_scan += \
- lib/distribute.c \
- lib/filter.c \
- lib/filter_cli.c \
- lib/if.c \
- lib/if_rmap.c \
- lib/keychain.c \
- lib/lib_vty.c \
- lib/log_vty.c \
- lib/nexthop_group.c \
- lib/plist.c \
- lib/routemap.c \
- lib/routemap_cli.c \
- lib/spf_backoff.c \
- lib/thread.c \
- lib/vrf.c \
- lib/vty.c \
- # end
-# can be loaded as DSO - always include for vtysh
-vtysh_scan += lib/agentx.c
-
if SQLITE3
lib_libfrr_la_LIBADD += $(SQLITE3_LIBS)
lib_libfrr_la_SOURCES += lib/db.c
@@ -245,6 +224,7 @@ pkginclude_HEADERS += \
lib/ns.h \
lib/openbsd-queue.h \
lib/openbsd-tree.h \
+ lib/orr_msg.h \
lib/plist.h \
lib/prefix.h \
lib/printfrr.h \
@@ -346,7 +326,6 @@ lib_libfrrsnmp_la_SOURCES = \
if CARES
lib_LTLIBRARIES += lib/libfrrcares.la
pkginclude_HEADERS += lib/resolver.h
-vtysh_scan += lib/resolver.c
endif
lib_libfrrcares_la_CFLAGS = $(AM_CFLAGS) $(CARES_CFLAGS)
@@ -477,13 +456,18 @@ SUFFIXES += .xref
# dependencies added in python/makefile.py
frr.xref:
- $(AM_V_XRELFO) $(CLIPPY) $(top_srcdir)/python/xrelfo.py -o $@ $^
+ $(AM_V_XRELFO) $(CLIPPY) $(top_srcdir)/python/xrelfo.py -o $@ -c vtysh/vtysh_cmd.c $^
all-am: frr.xref
clean-xref:
-rm -rf $(xrefs) frr.xref
clean-local: clean-xref
+CLEANFILES += vtysh/vtysh_cmd.c
+vtysh/vtysh_cmd.c: frr.xref
+ @test -f $@ || rm -f frr.xref || true
+ @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) frr.xref
+
## automake's "ylwrap" is a great piece of GNU software... not.
.l.c:
$(AM_V_LEX)$(am__skiplex) $(LEXCOMPILE) $<
diff --git a/lib/thread.c b/lib/thread.c
index 9eac9b410..4078634f7 100644
--- a/lib/thread.c
+++ b/lib/thread.c
@@ -102,9 +102,7 @@ unsigned long cputime_threshold = CONSUMED_TIME_CHECK;
unsigned long walltime_threshold = CONSUMED_TIME_CHECK;
/* CLI start ---------------------------------------------------------------- */
-#ifndef VTYSH_EXTRACT_PL
#include "lib/thread_clippy.c"
-#endif
static unsigned int cpu_record_hash_key(const struct cpu_thread_history *a)
{
diff --git a/lib/vty.c b/lib/vty.c
index 92db07677..5fe8d8247 100644
--- a/lib/vty.c
+++ b/lib/vty.c
@@ -24,11 +24,16 @@
#include <lib/version.h>
#include <sys/types.h>
#include <sys/types.h>
-#ifdef HAVE_LIBPCREPOSIX
+#ifdef HAVE_LIBPCRE2_POSIX
+#ifndef _FRR_PCRE2_POSIX
+#define _FRR_PCRE2_POSIX
+#include <pcre2posix.h>
+#endif /* _FRR_PCRE2_POSIX */
+#elif defined(HAVE_LIBPCREPOSIX)
#include <pcreposix.h>
#else
#include <regex.h>
-#endif /* HAVE_LIBPCREPOSIX */
+#endif /* HAVE_LIBPCRE2_POSIX */
#include <stdio.h>
#include "linklist.h"
@@ -53,9 +58,7 @@
#include <arpa/telnet.h>
#include <termios.h>
-#ifndef VTYSH_EXTRACT_PL
#include "lib/vty_clippy.c"
-#endif
DEFINE_MTYPE_STATIC(LIB, VTY, "VTY");
DEFINE_MTYPE_STATIC(LIB, VTY_SERV, "VTY server");
diff --git a/lib/vty.h b/lib/vty.h
index 430579c5a..0b3fd2443 100644
--- a/lib/vty.h
+++ b/lib/vty.h
@@ -22,11 +22,16 @@
#define _ZEBRA_VTY_H
#include <sys/types.h>
-#ifdef HAVE_LIBPCREPOSIX
+#ifdef HAVE_LIBPCRE2_POSIX
+#ifndef _FRR_PCRE2_POSIX
+#define _FRR_PCRE2_POSIX
+#include <pcre2posix.h>
+#endif /* _FRR_PCRE2_POSIX */
+#elif defined(HAVE_LIBPCREPOSIX)
#include <pcreposix.h>
#else
#include <regex.h>
-#endif /* HAVE_LIBPCREPOSIX */
+#endif /* HAVE_LIBPCRE2_POSIX */
#include "thread.h"
#include "log.h"
diff --git a/lib/zclient.c b/lib/zclient.c
index 8ec82ab7b..fd6eb7db0 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -1088,6 +1088,7 @@ int zapi_srv6_locator_chunk_encode(struct stream *s,
stream_putc(s, c->node_bits_length);
stream_putc(s, c->function_bits_length);
stream_putc(s, c->argument_bits_length);
+ stream_putc(s, c->flags);
return 0;
}
@@ -1109,6 +1110,7 @@ int zapi_srv6_locator_chunk_decode(struct stream *s,
STREAM_GETC(s, c->node_bits_length);
STREAM_GETC(s, c->function_bits_length);
STREAM_GETC(s, c->argument_bits_length);
+ STREAM_GETC(s, c->flags);
return 0;
stream_failure:
@@ -1166,6 +1168,10 @@ static int zapi_nhg_encode(struct stream *s, int cmd, struct zapi_nhg *api_nhg)
stream_putw(s, api_nhg->proto);
stream_putl(s, api_nhg->id);
+ stream_putw(s, api_nhg->resilience.buckets);
+ stream_putl(s, api_nhg->resilience.idle_timer);
+ stream_putl(s, api_nhg->resilience.unbalanced_timer);
+
if (cmd == ZEBRA_NHG_ADD) {
/* Nexthops */
zapi_nexthop_group_sort(api_nhg->nexthops,
@@ -2299,13 +2305,22 @@ static int zclient_handle_error(ZAPI_CALLBACK_ARGS)
return 0;
}
-static int link_params_set_value(struct stream *s, struct if_link_params *iflp)
+static int link_params_set_value(struct stream *s, struct interface *ifp)
{
+ uint8_t link_params_enabled;
+ struct if_link_params *iflp;
+ uint32_t bwclassnum;
+
+ iflp = if_link_params_get(ifp);
if (iflp == NULL)
- return -1;
+ iflp = if_link_params_init(ifp);
- uint32_t bwclassnum;
+ STREAM_GETC(s, link_params_enabled);
+ if (!link_params_enabled) {
+ if_link_params_free(ifp);
+ return 0;
+ }
STREAM_GETL(s, iflp->lp_status);
STREAM_GETL(s, iflp->te_metric);
@@ -2346,9 +2361,9 @@ struct interface *zebra_interface_link_params_read(struct stream *s,
bool *changed)
{
struct if_link_params *iflp;
- struct if_link_params iflp_copy;
+ struct if_link_params iflp_prev;
ifindex_t ifindex;
- bool params_changed = false;
+ bool iflp_prev_set;
STREAM_GETL(s, ifindex);
@@ -2361,22 +2376,33 @@ struct interface *zebra_interface_link_params_read(struct stream *s,
return NULL;
}
- if (ifp->link_params == NULL)
- params_changed = true;
-
- if ((iflp = if_link_params_get(ifp)) == NULL)
- return NULL;
-
- memcpy(&iflp_copy, iflp, sizeof(iflp_copy));
+ if (if_link_params_get(ifp)) {
+ iflp_prev_set = true;
+ memcpy(&iflp_prev, ifp->link_params, sizeof(iflp_prev));
+ } else
+ iflp_prev_set = false;
- if (link_params_set_value(s, iflp) != 0)
+ /* read the link_params from stream
+ * Free ifp->link_params if the stream has no params
+ * to means that link-params are not enabled on links.
+ */
+ if (link_params_set_value(s, ifp) != 0)
goto stream_failure;
- if (memcmp(&iflp_copy, iflp, sizeof(iflp_copy)))
- params_changed = true;
+ if (changed == NULL)
+ return ifp;
- if (changed)
- *changed = params_changed;
+ iflp = if_link_params_get(ifp);
+
+ if (iflp_prev_set && iflp) {
+ if (memcmp(&iflp_prev, iflp, sizeof(iflp_prev)))
+ *changed = true;
+ else
+ *changed = false;
+ } else if (!iflp_prev_set && !iflp)
+ *changed = false;
+ else
+ *changed = true;
return ifp;
@@ -2415,10 +2441,8 @@ static void zebra_interface_if_set_value(struct stream *s,
/* Read Traffic Engineering status */
link_params_status = stream_getc(s);
/* Then, Traffic Engineering parameters if any */
- if (link_params_status) {
- struct if_link_params *iflp = if_link_params_get(ifp);
- link_params_set_value(s, iflp);
- }
+ if (link_params_status)
+ link_params_set_value(s, ifp);
nexthop_group_interface_state_change(ifp, old_ifindex);
@@ -2435,12 +2459,20 @@ size_t zebra_interface_link_params_write(struct stream *s,
struct if_link_params *iflp;
int i;
- if (s == NULL || ifp == NULL || ifp->link_params == NULL)
+ if (s == NULL || ifp == NULL)
return 0;
iflp = ifp->link_params;
w = 0;
+ /* encode if link_params is enabled */
+ if (iflp) {
+ w += stream_putc(s, true);
+ } else {
+ w += stream_putc(s, false);
+ return w;
+ }
+
w += stream_putl(s, iflp->lp_status);
w += stream_putl(s, iflp->te_metric);
diff --git a/lib/zclient.h b/lib/zclient.h
index c3ea2a16f..731769abf 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -35,6 +35,8 @@ struct zclient;
/* For union g_addr */
#include "nexthop.h"
+/* For resilience */
+#include "nexthop_group.h"
/* For union pw_protocol_fields */
#include "pw.h"
@@ -100,6 +102,8 @@ enum zserv_client_capabilities {
extern struct sockaddr_storage zclient_addr;
extern socklen_t zclient_addr_len;
+#define ZAPI_ORR_FLAG_UNICAST 0x01
+
/* Zebra message types. */
typedef enum {
ZEBRA_INTERFACE_ADD,
@@ -461,6 +465,8 @@ struct zapi_nhg {
uint16_t proto;
uint32_t id;
+ struct nhg_resilience resilience;
+
uint16_t nexthop_num;
struct zapi_nexthop nexthops[MULTIPATH_NUM];
@@ -538,6 +544,13 @@ struct zapi_route {
*/
#define ZEBRA_FLAG_OFFLOAD_FAILED 0x200
+/*
+ * This flag lets us know that we think the route entry
+ * received has caused us to be out of sync with the
+ * kernel (NLM_F_APPEND at the very least )
+ */
+#define ZEBRA_FLAG_OUTOFSYNC 0x400
+
/* The older XXX_MESSAGE flags live here */
uint32_t message;
@@ -1229,6 +1242,10 @@ enum zapi_opaque_registry {
LDP_RLFA_UNREGISTER_ALL = 8,
/* Announce LDP labels associated to a previously registered RLFA */
LDP_RLFA_LABELS = 9,
+ /* Register for IGP METRIC with OSPF/ISIS */
+ ORR_IGP_METRIC_REGISTER = 10,
+ /* Send SPF data to BGP */
+ ORR_IGP_METRIC_UPDATE = 11
};
/* Send the hello message.
diff --git a/lib/zebra.h b/lib/zebra.h
index 53ae5b4e9..b2f5e5a84 100644
--- a/lib/zebra.h
+++ b/lib/zebra.h
@@ -202,9 +202,9 @@
#endif /* HAVE_GLIBC_BACKTRACE */
/* Local includes: */
-#if !(defined(__GNUC__) || defined(VTYSH_EXTRACT_PL))
+#if !defined(__GNUC__)
#define __attribute__(x)
-#endif /* !__GNUC__ || VTYSH_EXTRACT_PL */
+#endif /* !__GNUC__ */
#include <assert.h>
diff --git a/lib/zlog_5424_cli.c b/lib/zlog_5424_cli.c
index dd8dbfaff..5eebda9de 100644
--- a/lib/zlog_5424_cli.c
+++ b/lib/zlog_5424_cli.c
@@ -158,9 +158,7 @@ static int reconf_clear_dst(struct zlog_cfg_5424_user *cfg, struct vty *vty)
return reconf_dst(cfg, vty);
}
-#ifndef VTYSH_EXTRACT_PL
#include "lib/zlog_5424_cli_clippy.c"
-#endif
DEFPY_NOSH(log_5424_target,
log_5424_target_cmd,
diff --git a/nhrpd/nhrp_vty.c b/nhrpd/nhrp_vty.c
index 3a8baa234..53ba9eb12 100644
--- a/nhrpd/nhrp_vty.c
+++ b/nhrpd/nhrp_vty.c
@@ -126,6 +126,8 @@ DEFUN_NOSH(show_debugging_nhrp, show_debugging_nhrp_cmd,
debug_flags_desc[i].str);
}
+ cmd_show_lib_debugs(vty);
+
return CMD_SUCCESS;
}
diff --git a/nhrpd/subdir.am b/nhrpd/subdir.am
index dc0c162c8..227ff6c67 100644
--- a/nhrpd/subdir.am
+++ b/nhrpd/subdir.am
@@ -4,7 +4,6 @@
if NHRPD
sbin_PROGRAMS += nhrpd/nhrpd
-vtysh_scan += nhrpd/nhrp_vty.c
vtysh_daemons += nhrpd
man8 += $(MANBUILD)/frr-nhrpd.8
endif
diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c
index a0cb45579..6a4236e71 100644
--- a/ospf6d/ospf6_area.c
+++ b/ospf6d/ospf6_area.c
@@ -39,6 +39,8 @@
#include "ospf6_spf.h"
#include "ospf6_top.h"
#include "ospf6_area.h"
+#include "ospf6_message.h"
+#include "ospf6_neighbor.h"
#include "ospf6_interface.h"
#include "ospf6_intra.h"
#include "ospf6_abr.h"
@@ -47,9 +49,7 @@
#include "ospf6d.h"
#include "lib/json.h"
#include "ospf6_nssa.h"
-#ifndef VTYSH_EXTRACT_PL
#include "ospf6d/ospf6_area_clippy.c"
-#endif
DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_AREA, "OSPF6 area");
DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_PLISTNAME, "Prefix list name");
@@ -348,9 +348,17 @@ void ospf6_area_delete(struct ospf6_area *oa)
* deleting an area.
* So just detach the interface from the area and
* keep it around. */
- for (ALL_LIST_ELEMENTS_RO(oa->if_list, n, oi))
+ for (ALL_LIST_ELEMENTS_RO(oa->if_list, n, oi)) {
oi->area = NULL;
+ struct listnode *node;
+ struct listnode *nnode;
+ struct ospf6_neighbor *on;
+
+ for (ALL_LIST_ELEMENTS(oi->neighbor_list, node, nnode, on))
+ ospf6_neighbor_delete(on);
+ }
+
list_delete(&oa->if_list);
ospf6_lsdb_delete(oa->lsdb);
diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c
index ae3ce2f0c..07061b6f5 100644
--- a/ospf6d/ospf6_asbr.c
+++ b/ospf6d/ospf6_asbr.c
@@ -65,9 +65,7 @@ static void ospf6_asbr_redistribute_set(struct ospf6 *ospf6, int type);
static void ospf6_asbr_redistribute_unset(struct ospf6 *ospf6,
struct ospf6_redist *red, int type);
-#ifndef VTYSH_EXTRACT_PL
#include "ospf6d/ospf6_asbr_clippy.c"
-#endif
unsigned char conf_debug_ospf6_asbr = 0;
@@ -2206,10 +2204,10 @@ static const struct route_map_rule_cmd ospf6_routemap_rule_set_tag_cmd = {
/* add "set metric-type" */
DEFUN_YANG (ospf6_routemap_set_metric_type, ospf6_routemap_set_metric_type_cmd,
"set metric-type <type-1|type-2>",
- "Set value\n"
- "Type of metric\n"
- "OSPF6 external type 1 metric\n"
- "OSPF6 external type 2 metric\n")
+ SET_STR
+ "Type of metric for destination routing protocol\n"
+ "OSPF[6] external type 1 metric\n"
+ "OSPF[6] external type 2 metric\n")
{
char *ext = argv[2]->text;
@@ -2228,10 +2226,10 @@ DEFUN_YANG (ospf6_routemap_set_metric_type, ospf6_routemap_set_metric_type_cmd,
DEFUN_YANG (ospf6_routemap_no_set_metric_type, ospf6_routemap_no_set_metric_type_cmd,
"no set metric-type [<type-1|type-2>]",
NO_STR
- "Set value\n"
- "Type of metric\n"
- "OSPF6 external type 1 metric\n"
- "OSPF6 external type 2 metric\n")
+ SET_STR
+ "Type of metric for destination routing protocol\n"
+ "OSPF[6] external type 1 metric\n"
+ "OSPF[6] external type 2 metric\n")
{
const char *xpath =
"./set-action[action='frr-ospf-route-map:metric-type']";
@@ -3169,6 +3167,14 @@ void ospf6_external_aggregator_free(struct ospf6_external_aggr_rt *aggr)
hash_clean(aggr->match_extnl_hash,
ospf6_aggr_unlink_external_info);
+ if (aggr->route) {
+ if (aggr->route->route_option)
+ XFREE(MTYPE_OSPF6_EXTERNAL_INFO,
+ aggr->route->route_option);
+
+ ospf6_route_delete(aggr->route);
+ }
+
if (IS_OSPF6_DEBUG_AGGR)
zlog_debug("%s: Release the aggregator Address(%pFX)",
__func__,
diff --git a/ospf6d/ospf6_gr.c b/ospf6d/ospf6_gr.c
index d7de66c66..1f7fefa04 100644
--- a/ospf6d/ospf6_gr.c
+++ b/ospf6d/ospf6_gr.c
@@ -42,9 +42,7 @@
#include "ospf6d/ospf6_intra.h"
#include "ospf6d/ospf6_spf.h"
#include "ospf6d/ospf6_gr.h"
-#ifndef VTYSH_EXTRACT_PL
#include "ospf6d/ospf6_gr_clippy.c"
-#endif
static void ospf6_gr_nvm_delete(struct ospf6 *ospf6);
diff --git a/ospf6d/ospf6_gr_helper.c b/ospf6d/ospf6_gr_helper.c
index f8b37d803..771a71024 100644
--- a/ospf6d/ospf6_gr_helper.c
+++ b/ospf6d/ospf6_gr_helper.c
@@ -49,9 +49,7 @@
#include "ospf6d.h"
#include "ospf6_gr.h"
#include "lib/json.h"
-#ifndef VTYSH_EXTRACT_PL
#include "ospf6d/ospf6_gr_helper_clippy.c"
-#endif
DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_GR_HELPER, "OSPF6 Graceful restart helper");
@@ -982,6 +980,11 @@ CPP_NOTICE("Remove JSON object commands with keys starting with capital")
.last_exit_reason]);
}
+ if (ospf6->ospf6_helper_cfg.active_restarter_cnt)
+ json_object_int_add(
+ json, "activeRestarterCnt",
+ ospf6->ospf6_helper_cfg.active_restarter_cnt);
+
if (OSPF6_HELPER_ENABLE_RTR_COUNT(ospf6)) {
struct json_object *json_rid_array =
json_object_new_array();
diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c
index 155374d3f..ed228f46a 100644
--- a/ospf6d/ospf6_interface.c
+++ b/ospf6d/ospf6_interface.c
@@ -37,6 +37,7 @@
#include "ospf6_route.h"
#include "ospf6_area.h"
#include "ospf6_abr.h"
+#include "ospf6_nssa.h"
#include "ospf6_interface.h"
#include "ospf6_neighbor.h"
#include "ospf6_intra.h"
@@ -1116,14 +1117,21 @@ static int ospf6_interface_show(struct vty *vty, struct interface *ifp,
oi->dead_interval);
json_object_int_add(json_obj, "timerIntervalsConfigRetransmit",
oi->rxmt_interval);
+ json_object_boolean_add(
+ json_obj, "timerPassiveIface",
+ !!CHECK_FLAG(oi->flag, OSPF6_INTERFACE_PASSIVE));
} else {
vty_out(vty, " State %s, Transmit Delay %d sec, Priority %d\n",
ospf6_interface_state_str[oi->state], oi->transdelay,
oi->priority);
vty_out(vty, " Timer intervals configured:\n");
- vty_out(vty, " Hello %d(%pTHd), Dead %d, Retransmit %d\n",
- oi->hello_interval, oi->thread_send_hello,
- oi->dead_interval, oi->rxmt_interval);
+ if (!CHECK_FLAG(oi->flag, OSPF6_INTERFACE_PASSIVE))
+ vty_out(vty,
+ " Hello %d(%pTHd), Dead %d, Retransmit %d\n",
+ oi->hello_interval, oi->thread_send_hello,
+ oi->dead_interval, oi->rxmt_interval);
+ else
+ vty_out(vty, " No Hellos (Passive interface)\n");
}
inet_ntop(AF_INET, &oi->drouter, drouter, sizeof(drouter));
@@ -1736,8 +1744,10 @@ void ospf6_interface_start(struct ospf6_interface *oi)
ospf6_interface_enable(oi);
/* If the router is ABR, originate summary routes */
- if (ospf6_check_and_set_router_abr(ospf6))
+ if (ospf6_check_and_set_router_abr(ospf6)) {
ospf6_abr_enable_area(oa);
+ ospf6_schedule_abr_task(ospf6);
+ }
}
void ospf6_interface_stop(struct ospf6_interface *oi)
diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c
index 779076f38..2792820a5 100644
--- a/ospf6d/ospf6_lsa.c
+++ b/ospf6d/ospf6_lsa.c
@@ -46,9 +46,7 @@
#include "ospf6_flood.h"
#include "ospf6d.h"
-#ifndef VTYSH_EXTRACT_PL
#include "ospf6d/ospf6_lsa_clippy.c"
-#endif
DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA, "OSPF6 LSA");
DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA_HEADER, "OSPF6 LSA header");
diff --git a/ospf6d/ospf6_nssa.c b/ospf6d/ospf6_nssa.c
index b1bff69f0..f35c9df4a 100644
--- a/ospf6d/ospf6_nssa.c
+++ b/ospf6d/ospf6_nssa.c
@@ -49,9 +49,7 @@
#include "ospf6_asbr.h"
#include "ospf6d.h"
#include "ospf6_nssa.h"
-#ifndef VTYSH_EXTRACT_PL
#include "ospf6d/ospf6_nssa_clippy.c"
-#endif
DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA, "OSPF6 LSA");
unsigned char config_debug_ospf6_nssa = 0;
diff --git a/ospf6d/ospf6_nssa.h b/ospf6d/ospf6_nssa.h
index 02234cc8b..3cc45d900 100644
--- a/ospf6d/ospf6_nssa.h
+++ b/ospf6d/ospf6_nssa.h
@@ -45,7 +45,7 @@ extern unsigned char config_debug_ospf6_nssa;
#define OSPF6_LSA_APPROVED 0x08
#define OSPF6_LSA_LOCAL_XLT 0x40
-#define OSPF6_ABR_TASK_DELAY 7
+#define OSPF6_ABR_TASK_DELAY 5
int ospf6_area_nssa_no_summary_set(struct ospf6 *ospf6, struct in_addr area_id);
int ospf6_area_nssa_unset(struct ospf6 *ospf6, struct ospf6_area *area);
diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c
index 8e964393f..db94b85b1 100644
--- a/ospf6d/ospf6_route.c
+++ b/ospf6d/ospf6_route.c
@@ -37,9 +37,7 @@
#include "ospf6_interface.h"
#include "ospf6d.h"
#include "ospf6_zebra.h"
-#ifndef VTYSH_EXTRACT_PL
#include "ospf6d/ospf6_route_clippy.c"
-#endif
DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_ROUTE, "OSPF6 route");
DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_ROUTE_TABLE, "OSPF6 route table");
@@ -1360,7 +1358,7 @@ static void ospf6_route_show_table_summary(struct vty *vty,
struct ospf6_route *route, *prev = NULL;
int i, pathtype[OSPF6_PATH_TYPE_MAX];
unsigned int number = 0;
- int nh_count = 0, nhinval = 0, ecmp = 0;
+ int nh_count = 0, ecmp = 0;
int alternative = 0, destination = 0;
char path_str[30];
@@ -1374,9 +1372,7 @@ static void ospf6_route_show_table_summary(struct vty *vty,
else
alternative++;
nh_count = ospf6_num_nexthops(route->nh_list);
- if (!nh_count)
- nhinval++;
- else if (nh_count > 1)
+ if (nh_count > 1)
ecmp++;
pathtype[route->path.type]++;
number++;
diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c
index d48e85ced..eb89a14cd 100644
--- a/ospf6d/ospf6_top.c
+++ b/ospf6d/ospf6_top.c
@@ -65,9 +65,7 @@ FRR_CFG_DEFAULT_BOOL(OSPF6_LOG_ADJACENCY_CHANGES,
{ .val_bool = false },
);
-#ifndef VTYSH_EXTRACT_PL
#include "ospf6d/ospf6_top_clippy.c"
-#endif
/* global ospf6d variable */
static struct ospf6_master ospf6_master;
diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c
index a16f4f73e..fe742b912 100644
--- a/ospf6d/ospf6d.c
+++ b/ospf6d/ospf6d.c
@@ -115,6 +115,8 @@ DEFUN_NOSH (show_debugging_ospf6,
config_write_ospf6_debug(vty);
+ cmd_show_lib_debugs(vty);
+
return CMD_SUCCESS;
}
diff --git a/ospf6d/subdir.am b/ospf6d/subdir.am
index cf863ff52..3dff03956 100644
--- a/ospf6d/subdir.am
+++ b/ospf6d/subdir.am
@@ -5,27 +5,6 @@
if OSPF6D
noinst_LIBRARIES += ospf6d/libospf6.a
sbin_PROGRAMS += ospf6d/ospf6d
-vtysh_scan += \
- ospf6d/ospf6_nssa.c \
- ospf6d/ospf6_abr.c \
- ospf6d/ospf6_asbr.c \
- ospf6d/ospf6_area.c \
- ospf6d/ospf6_bfd.c \
- ospf6d/ospf6_flood.c \
- ospf6d/ospf6_gr.c \
- ospf6d/ospf6_gr_helper.c \
- ospf6d/ospf6_interface.c \
- ospf6d/ospf6_intra.c \
- ospf6d/ospf6_lsa.c \
- ospf6d/ospf6_message.c \
- ospf6d/ospf6_neighbor.c \
- ospf6d/ospf6_route.c \
- ospf6d/ospf6_spf.c \
- ospf6d/ospf6_top.c \
- ospf6d/ospf6_zebra.c \
- ospf6d/ospf6d.c \
- ospf6d/ospf6_auth_trailer.c \
- # end
vtysh_daemons += ospf6d
if SNMP
module_LTLIBRARIES += ospf6d/ospf6d_snmp.la
diff --git a/ospfclient/ospf_apiclient.c b/ospfclient/ospf_apiclient.c
index b5e6389d4..05c5e7789 100644
--- a/ospfclient/ospf_apiclient.c
+++ b/ospfclient/ospf_apiclient.c
@@ -481,8 +481,9 @@ int ospf_apiclient_lsa_originate(struct ospf_apiclient *oclient,
}
int ospf_apiclient_lsa_delete(struct ospf_apiclient *oclient,
- struct in_addr area_id, uint8_t lsa_type,
- uint8_t opaque_type, uint32_t opaque_id)
+ struct in_addr addr, uint8_t lsa_type,
+ uint8_t opaque_type, uint32_t opaque_id,
+ uint8_t flags)
{
struct msg *msg;
int rc;
@@ -496,8 +497,8 @@ int ospf_apiclient_lsa_delete(struct ospf_apiclient *oclient,
/* opaque_id is in host byte order and will be converted
* to network byte order by new_msg_delete_request */
- msg = new_msg_delete_request(ospf_apiclient_get_seqnr(), area_id,
- lsa_type, opaque_type, opaque_id);
+ msg = new_msg_delete_request(ospf_apiclient_get_seqnr(), addr, lsa_type,
+ opaque_type, opaque_id, flags);
rc = ospf_apiclient_send_request(oclient, msg);
return rc;
diff --git a/ospfclient/ospf_apiclient.h b/ospfclient/ospf_apiclient.h
index 6d1eb7f64..b904937c2 100644
--- a/ospfclient/ospf_apiclient.h
+++ b/ospfclient/ospf_apiclient.h
@@ -94,8 +94,9 @@ int ospf_apiclient_lsa_originate(struct ospf_apiclient *oclient,
/* Synchronous request to delete opaque LSA. Parameter opaque_id is in
host byte order */
int ospf_apiclient_lsa_delete(struct ospf_apiclient *oclient,
- struct in_addr area_id, uint8_t lsa_type,
- uint8_t opaque_type, uint32_t opaque_id);
+ struct in_addr addr, uint8_t lsa_type,
+ uint8_t opaque_type, uint32_t opaque_id,
+ uint8_t flags);
/* Fetch async message and handle it */
int ospf_apiclient_handle_async(struct ospf_apiclient *oclient);
diff --git a/ospfclient/ospfclient.c b/ospfclient/ospfclient.c
index 3cfee7d57..edf814184 100644
--- a/ospfclient/ospfclient.c
+++ b/ospfclient/ospfclient.c
@@ -98,9 +98,10 @@ static void lsa_delete(struct thread *t)
printf("Deleting LSA... ");
rc = ospf_apiclient_lsa_delete(oclient, area_id,
- atoi(args[2]), /* lsa type */
- atoi(args[3]), /* opaque type */
- atoi(args[4])); /* opaque ID */
+ atoi(args[2]), /* lsa type */
+ atoi(args[3]), /* opaque type */
+ atoi(args[4]), /* opaque ID */
+ 0); /* send data in withdrawals */
printf("done, return code is = %d\n", rc);
}
diff --git a/ospfclient/ospfclient.py b/ospfclient/ospfclient.py
index c7cfc88b9..8e3c68445 100755
--- a/ospfclient/ospfclient.py
+++ b/ospfclient/ospfclient.py
@@ -62,13 +62,16 @@ smsg_info = {
MSG_REGISTER_EVENT: ("REGISTER_EVENT", FMT_LSA_FILTER),
MSG_SYNC_LSDB: ("SYNC_LSDB", FMT_LSA_FILTER),
MSG_ORIGINATE_REQUEST: ("ORIGINATE_REQUEST", ">II" + FMT_LSA_HEADER[1:]),
- MSG_DELETE_REQUEST: ("DELETE_REQUEST", ">IBBxxL"),
+ MSG_DELETE_REQUEST: ("DELETE_REQUEST", ">IBBxBL"),
MSG_SYNC_REACHABLE: ("MSG_SYNC_REACHABLE", ""),
MSG_SYNC_ISM: ("MSG_SYNC_ISM", ""),
MSG_SYNC_NSM: ("MSG_SYNC_NSM", ""),
MSG_SYNC_ROUTER_ID: ("MSG_SYNC_ROUTER_ID", ""),
}
+# OSPF API MSG Delete Flag.
+OSPF_API_DEL_ZERO_LEN_LSA = 0x01 # send withdrawal with no LSA data
+
# --------------------------
# Messages from OSPF daemon.
# --------------------------
@@ -842,7 +845,7 @@ class OspfOpaqueClient(OspfApiClient):
await self._assure_opaque_ready(lsa_type, otype)
await self.msg_send_raises(mt, msg)
- async def delete_opaque_data(self, addr, lsa_type, otype, oid):
+ async def delete_opaque_data(self, addr, lsa_type, otype, oid, flags=0):
"""Delete an instance of opaque data.
Delete an instance of opaque data. This call will register for the given
@@ -854,6 +857,7 @@ class OspfOpaqueClient(OspfApiClient):
otype: (octet) opaque type. Note: the type will be registered if the user
has not explicity done that yet with `register_opaque_data`.
oid: (3 octets) ID of this opaque data
+ flags: (octet) optional flags (e.g., OSPF_API_DEL_ZERO_LEN_LSA, defaults to no flags)
Raises:
See `msg_send_raises`
"""
@@ -862,7 +866,7 @@ class OspfOpaqueClient(OspfApiClient):
mt = MSG_DELETE_REQUEST
await self._assure_opaque_ready(lsa_type, otype)
- mp = struct.pack(msg_fmt[mt], int(addr), lsa_type, otype, oid)
+ mp = struct.pack(msg_fmt[mt], int(addr), lsa_type, otype, flags, oid)
await self.msg_send_raises(mt, mp)
async def register_opaque_data(self, lsa_type, otype, callback=None):
@@ -1099,6 +1103,12 @@ async def async_main(args):
for action in args.actions:
_s = action.split(",")
what = _s.pop(False)
+ if what.casefold() == "wait":
+ stime = int(_s.pop(False))
+ logging.info("waiting %s seconds", stime)
+ await asyncio.sleep(stime)
+ logging.info("wait complete: %s seconds", stime)
+ continue
ltype = int(_s.pop(False))
if ltype == 11:
addr = ip(0)
@@ -1109,23 +1119,28 @@ async def async_main(args):
except ValueError:
addr = ip(aval)
oargs = [addr, ltype, int(_s.pop(False)), int(_s.pop(False))]
- assert len(_s) <= 1, "Bad format for action argument"
- try:
- b = bytes.fromhex(_s.pop(False))
- except IndexError:
- b = b""
- logging.info("opaque data is %s octets", len(b))
- # Needs to be multiple of 4 in length
- mod = len(b) % 4
- if mod:
- b += b"\x00" * (4 - mod)
- logging.info("opaque padding to %s octets", len(b))
-
if what.casefold() == "add":
+ try:
+ b = bytes.fromhex(_s.pop(False))
+ except IndexError:
+ b = b""
+ logging.info("opaque data is %s octets", len(b))
+ # Needs to be multiple of 4 in length
+ mod = len(b) % 4
+ if mod:
+ b += b"\x00" * (4 - mod)
+ logging.info("opaque padding to %s octets", len(b))
+
await c.add_opaque_data(*oargs, b)
else:
assert what.casefold().startswith("del")
- await c.delete_opaque_data(*oargs)
+ f = 0
+ if len(_s) >= 1:
+ try:
+ f = int(_s.pop(False))
+ except IndexError:
+ f = 0
+ await c.delete_opaque_data(*oargs, f)
if args.exit:
return 0
except Exception as error:
@@ -1147,7 +1162,9 @@ def main(*args):
ap.add_argument("--server", default="localhost", help="OSPF API server")
ap.add_argument("-v", "--verbose", action="store_true", help="be verbose")
ap.add_argument(
- "actions", nargs="*", help="(ADD|DEL),LSATYPE,[ADDR,],OTYPE,OID,[HEXDATA]"
+ "actions",
+ nargs="*",
+ help="(ADD|DEL),LSATYPE,[ADDR,],OTYPE,OID,[HEXDATA|DEL_FLAG]",
)
args = ap.parse_args()
diff --git a/ospfd/ospf_abr.h b/ospfd/ospf_abr.h
index e15f4a6bf..c523638fb 100644
--- a/ospfd/ospf_abr.h
+++ b/ospfd/ospf_abr.h
@@ -22,7 +22,7 @@
#ifndef _ZEBRA_OSPF_ABR_H
#define _ZEBRA_OSPF_ABR_H
-#define OSPF_ABR_TASK_DELAY 7
+#define OSPF_ABR_TASK_DELAY 5
#define OSPF_AREA_RANGE_ADVERTISE (1 << 0)
#define OSPF_AREA_RANGE_SUBSTITUTE (1 << 1)
diff --git a/ospfd/ospf_api.c b/ospfd/ospf_api.c
index 8636db450..9a134d033 100644
--- a/ospfd/ospf_api.c
+++ b/ospfd/ospf_api.c
@@ -532,16 +532,17 @@ struct msg *new_msg_originate_request(uint32_t seqnum, struct in_addr ifaddr,
return msg_new(MSG_ORIGINATE_REQUEST, omsg, seqnum, omsglen);
}
-struct msg *new_msg_delete_request(uint32_t seqnum, struct in_addr area_id,
+struct msg *new_msg_delete_request(uint32_t seqnum, struct in_addr addr,
uint8_t lsa_type, uint8_t opaque_type,
- uint32_t opaque_id)
+ uint32_t opaque_id, uint8_t flags)
{
struct msg_delete_request dmsg;
- dmsg.area_id = area_id;
+ dmsg.addr = addr;
dmsg.lsa_type = lsa_type;
dmsg.opaque_type = opaque_type;
dmsg.opaque_id = htonl(opaque_id);
memset(&dmsg.pad, 0, sizeof(dmsg.pad));
+ dmsg.flags = flags;
return msg_new(MSG_DELETE_REQUEST, &dmsg, seqnum,
sizeof(struct msg_delete_request));
diff --git a/ospfd/ospf_api.h b/ospfd/ospf_api.h
index 51c8c52ce..6f569e962 100644
--- a/ospfd/ospf_api.h
+++ b/ospfd/ospf_api.h
@@ -185,11 +185,19 @@ struct msg_originate_request {
struct lsa_header data;
};
+
+/* OSPF API MSG Delete Flag. */
+#define OSPF_API_DEL_ZERO_LEN_LSA 0x01 /* send withdrawal with no LSA data */
+
+#define IS_DEL_ZERO_LEN_LSA(x) ((x)->flags & OSPF_API_DEL_ZERO_LEN_LSA)
+
struct msg_delete_request {
- struct in_addr area_id; /* "0.0.0.0" for AS-external opaque LSAs */
+ struct in_addr addr; /* intf IP for link local, area for type 10,
+ "0.0.0.0" for AS-external */
uint8_t lsa_type;
uint8_t opaque_type;
- uint8_t pad[2]; /* padding */
+ uint8_t pad; /* padding */
+ uint8_t flags; /* delete flags */
uint32_t opaque_id;
};
@@ -311,10 +319,9 @@ extern struct msg *new_msg_originate_request(uint32_t seqnum,
struct in_addr ifaddr,
struct in_addr area_id,
struct lsa_header *data);
-extern struct msg *new_msg_delete_request(uint32_t seqnum,
- struct in_addr area_id,
+extern struct msg *new_msg_delete_request(uint32_t seqnum, struct in_addr addr,
uint8_t lsa_type, uint8_t opaque_type,
- uint32_t opaque_id);
+ uint32_t opaque_id, uint8_t flags);
/* Messages sent by OSPF daemon */
extern struct msg *new_msg_reply(uint32_t seqnum, uint8_t rc);
diff --git a/ospfd/ospf_apiserver.c b/ospfd/ospf_apiserver.c
index f5ed77dab..0c2ee0c4f 100644
--- a/ospfd/ospf_apiserver.c
+++ b/ospfd/ospf_apiserver.c
@@ -1924,6 +1924,7 @@ int ospf_apiserver_handle_delete_request(struct ospf_apiserver *apiserv,
struct msg_delete_request *dmsg;
struct ospf_lsa *old;
struct ospf_area *area = NULL;
+ struct ospf_interface *oi = NULL;
struct in_addr id;
int lsa_type, opaque_type;
int rc = 0;
@@ -1938,11 +1939,20 @@ int ospf_apiserver_handle_delete_request(struct ospf_apiserver *apiserv,
/* Lookup area for link-local and area-local opaque LSAs */
switch (dmsg->lsa_type) {
case OSPF_OPAQUE_LINK_LSA:
+ oi = ospf_apiserver_if_lookup_by_addr(dmsg->addr);
+ if (!oi) {
+ zlog_warn("%s: unknown interface %pI4", __func__,
+ &dmsg->addr);
+ rc = OSPF_API_NOSUCHINTERFACE;
+ goto out;
+ }
+ area = oi->area;
+ break;
case OSPF_OPAQUE_AREA_LSA:
- area = ospf_area_lookup_by_area_id(ospf, dmsg->area_id);
+ area = ospf_area_lookup_by_area_id(ospf, dmsg->addr);
if (!area) {
zlog_warn("%s: unknown area %pI4", __func__,
- &dmsg->area_id);
+ &dmsg->addr);
rc = OSPF_API_NOSUCHAREA;
goto out;
}
@@ -1987,6 +1997,11 @@ int ospf_apiserver_handle_delete_request(struct ospf_apiserver *apiserv,
goto out;
}
+ if (IS_DEL_ZERO_LEN_LSA(dmsg)) {
+ /* minimize the size of the withdrawal: */
+ old->opaque_zero_len_delete = 1;
+ }
+
/* Schedule flushing of LSA from LSDB */
/* NB: Multiple scheduling will produce a warning message, but harmless.
*/
diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c
index 258a93fb1..a47ed8d67 100644
--- a/ospfd/ospf_dump.c
+++ b/ospfd/ospf_dump.c
@@ -42,9 +42,7 @@
#include "ospfd/ospf_dump.h"
#include "ospfd/ospf_packet.h"
#include "ospfd/ospf_network.h"
-#ifndef VTYSH_EXTRACT_PL
#include "ospfd/ospf_dump_clippy.c"
-#endif
/* Configuration debug option variables. */
unsigned long conf_debug_ospf_packet[5] = {0, 0, 0, 0, 0};
@@ -54,15 +52,16 @@ unsigned long conf_debug_ospf_nsm = 0;
unsigned long conf_debug_ospf_lsa = 0;
unsigned long conf_debug_ospf_zebra = 0;
unsigned long conf_debug_ospf_nssa = 0;
-unsigned long conf_debug_ospf_te = 0;
+unsigned long conf_debug_ospf_te;
unsigned long conf_debug_ospf_ext = 0;
-unsigned long conf_debug_ospf_sr = 0;
-unsigned long conf_debug_ospf_ti_lfa = 0;
-unsigned long conf_debug_ospf_defaultinfo = 0;
-unsigned long conf_debug_ospf_ldp_sync = 0;
-unsigned long conf_debug_ospf_gr = 0;
+unsigned long conf_debug_ospf_sr;
+unsigned long conf_debug_ospf_ti_lfa;
+unsigned long conf_debug_ospf_defaultinfo;
+unsigned long conf_debug_ospf_ldp_sync;
+unsigned long conf_debug_ospf_gr;
unsigned long conf_debug_ospf_bfd;
unsigned long conf_debug_ospf_client_api;
+unsigned long conf_debug_ospf_orr;
/* Enable debug option variables -- valid only session. */
unsigned long term_debug_ospf_packet[5] = {0, 0, 0, 0, 0};
@@ -72,15 +71,16 @@ unsigned long term_debug_ospf_nsm = 0;
unsigned long term_debug_ospf_lsa = 0;
unsigned long term_debug_ospf_zebra = 0;
unsigned long term_debug_ospf_nssa = 0;
-unsigned long term_debug_ospf_te = 0;
+unsigned long term_debug_ospf_te;
unsigned long term_debug_ospf_ext = 0;
-unsigned long term_debug_ospf_sr = 0;
-unsigned long term_debug_ospf_ti_lfa = 0;
+unsigned long term_debug_ospf_sr;
+unsigned long term_debug_ospf_ti_lfa;
unsigned long term_debug_ospf_defaultinfo;
unsigned long term_debug_ospf_ldp_sync;
-unsigned long term_debug_ospf_gr = 0;
+unsigned long term_debug_ospf_gr;
unsigned long term_debug_ospf_bfd;
unsigned long term_debug_ospf_client_api;
+unsigned long term_debug_ospf_orr;
const char *ospf_redist_string(unsigned int route_type)
{
@@ -628,84 +628,9 @@ void ospf_packet_dump(struct stream *s)
stream_set_getp(s, gp);
}
-DEFUN (debug_ospf_packet,
+DEFPY (debug_ospf_packet,
debug_ospf_packet_cmd,
- "debug ospf [(1-65535)] packet <hello|dd|ls-request|ls-update|ls-ack|all> [<send [detail]|recv [detail]|detail>]",
- DEBUG_STR
- OSPF_STR
- "Instance ID\n"
- "OSPF packets\n"
- "OSPF Hello\n"
- "OSPF Database Description\n"
- "OSPF Link State Request\n"
- "OSPF Link State Update\n"
- "OSPF Link State Acknowledgment\n"
- "OSPF all packets\n"
- "Packet sent\n"
- "Detail Information\n"
- "Packet received\n"
- "Detail Information\n"
- "Detail Information\n")
-{
- int inst = (argv[2]->type == RANGE_TKN) ? 1 : 0;
- int detail = strmatch(argv[argc - 1]->text, "detail");
- int send = strmatch(argv[argc - (1 + detail)]->text, "send");
- int recv = strmatch(argv[argc - (1 + detail)]->text, "recv");
- char *packet = argv[3 + inst]->text;
-
- if (inst) // user passed instance ID
- {
- if (inst != ospf_instance)
- return CMD_NOT_MY_INSTANCE;
- }
-
- int type = 0;
- int flag = 0;
- int i;
-
- /* Check packet type. */
- if (strmatch(packet, "hello"))
- type = OSPF_DEBUG_HELLO;
- else if (strmatch(packet, "dd"))
- type = OSPF_DEBUG_DB_DESC;
- else if (strmatch(packet, "ls-request"))
- type = OSPF_DEBUG_LS_REQ;
- else if (strmatch(packet, "ls-update"))
- type = OSPF_DEBUG_LS_UPD;
- else if (strmatch(packet, "ls-ack"))
- type = OSPF_DEBUG_LS_ACK;
- else if (strmatch(packet, "all"))
- type = OSPF_DEBUG_ALL;
-
- /* Cases:
- * (none) = send + recv
- * detail = send + recv + detail
- * recv = recv
- * send = send
- * recv detail = recv + detail
- * send detail = send + detail
- */
- if (!send && !recv)
- send = recv = 1;
-
- flag |= (send) ? OSPF_DEBUG_SEND : 0;
- flag |= (recv) ? OSPF_DEBUG_RECV : 0;
- flag |= (detail) ? OSPF_DEBUG_DETAIL : 0;
-
- for (i = 0; i < 5; i++)
- if (type & (0x01 << i)) {
- if (vty->node == CONFIG_NODE)
- DEBUG_PACKET_ON(i, flag);
- else
- TERM_DEBUG_PACKET_ON(i, flag);
- }
-
- return CMD_SUCCESS;
-}
-
-DEFUN (no_debug_ospf_packet,
- no_debug_ospf_packet_cmd,
- "no debug ospf [(1-65535)] packet <hello|dd|ls-request|ls-update|ls-ack|all> [<send [detail]|recv [detail]|detail>]",
+ "[no$no] debug ospf [(1-65535)$inst] packet <hello|dd|ls-request|ls-update|ls-ack|all>$packet [<send$send [detail$detail]|recv$recv [detail$detail]|detail$detail>]",
NO_STR
DEBUG_STR
OSPF_STR
@@ -723,22 +648,13 @@ DEFUN (no_debug_ospf_packet,
"Detail Information\n"
"Detail Information\n")
{
- int inst = (argv[3]->type == RANGE_TKN) ? 1 : 0;
- int detail = strmatch(argv[argc - 1]->text, "detail");
- int send = strmatch(argv[argc - (1 + detail)]->text, "send");
- int recv = strmatch(argv[argc - (1 + detail)]->text, "recv");
- char *packet = argv[4 + inst]->text;
-
- if (inst) // user passed instance ID
- {
- if (inst != ospf_instance)
- return CMD_NOT_MY_INSTANCE;
- }
-
int type = 0;
int flag = 0;
int i;
+ if (inst && inst != ospf_instance)
+ return CMD_NOT_MY_INSTANCE;
+
/* Check packet type. */
if (strmatch(packet, "hello"))
type = OSPF_DEBUG_HELLO;
@@ -761,8 +677,10 @@ DEFUN (no_debug_ospf_packet,
* recv detail = recv + detail
* send detail = send + detail
*/
- if (!send && !recv)
- send = recv = 1;
+ if (!send && !recv) {
+ flag |= OSPF_DEBUG_SEND;
+ flag |= OSPF_DEBUG_RECV;
+ }
flag |= (send) ? OSPF_DEBUG_SEND : 0;
flag |= (recv) ? OSPF_DEBUG_RECV : 0;
@@ -770,10 +688,17 @@ DEFUN (no_debug_ospf_packet,
for (i = 0; i < 5; i++)
if (type & (0x01 << i)) {
- if (vty->node == CONFIG_NODE)
- DEBUG_PACKET_OFF(i, flag);
- else
- TERM_DEBUG_PACKET_OFF(i, flag);
+ if (vty->node == CONFIG_NODE) {
+ if (no)
+ DEBUG_PACKET_OFF(i, flag);
+ else
+ DEBUG_PACKET_ON(i, flag);
+ } else {
+ if (no)
+ TERM_DEBUG_PACKET_OFF(i, flag);
+ else
+ TERM_DEBUG_PACKET_ON(i, flag);
+ }
}
#ifdef DEBUG
@@ -1457,194 +1382,248 @@ DEFUN (no_debug_ospf_instance_nssa,
return CMD_SUCCESS;
}
-DEFUN (debug_ospf_te,
+DEFPY (debug_ospf_te,
debug_ospf_te_cmd,
- "debug ospf te",
- DEBUG_STR
- OSPF_STR
- "OSPF-TE information\n")
-{
- if (vty->node == CONFIG_NODE)
- CONF_DEBUG_ON(te, TE);
- TERM_DEBUG_ON(te, TE);
- return CMD_SUCCESS;
-}
-
-DEFUN (no_debug_ospf_te,
- no_debug_ospf_te_cmd,
- "no debug ospf te",
+ "[no$no] debug ospf [(1-65535)$instance] te",
NO_STR
DEBUG_STR
OSPF_STR
+ "Instance ID\n"
"OSPF-TE information\n")
{
- if (vty->node == CONFIG_NODE)
- CONF_DEBUG_OFF(te, TE);
- TERM_DEBUG_OFF(te, TE);
+ if (instance && instance != ospf_instance)
+ return CMD_NOT_MY_INSTANCE;
+
+ if (vty->node == CONFIG_NODE) {
+ if (no)
+ DEBUG_OFF(te, TE);
+ else
+ DEBUG_ON(te, TE);
+ } else {
+ if (no)
+ TERM_DEBUG_OFF(te, TE);
+ else
+ TERM_DEBUG_ON(te, TE);
+ }
+
return CMD_SUCCESS;
}
-DEFUN (debug_ospf_sr,
+DEFPY (debug_ospf_sr,
debug_ospf_sr_cmd,
- "debug ospf sr",
+ "[no$no] debug ospf [(1-65535)$instance] sr",
+ NO_STR
DEBUG_STR
OSPF_STR
+ "Instance ID\n"
"OSPF-SR information\n")
{
- if (vty->node == CONFIG_NODE)
- CONF_DEBUG_ON(sr, SR);
- TERM_DEBUG_ON(sr, SR);
+ if (instance && instance != ospf_instance)
+ return CMD_NOT_MY_INSTANCE;
+
+ if (vty->node == CONFIG_NODE) {
+ if (no)
+ DEBUG_OFF(sr, SR);
+ else
+ DEBUG_ON(sr, SR);
+ } else {
+ if (no)
+ TERM_DEBUG_OFF(sr, SR);
+ else
+ TERM_DEBUG_ON(sr, SR);
+ }
+
return CMD_SUCCESS;
}
-DEFUN (no_debug_ospf_sr,
- no_debug_ospf_sr_cmd,
- "no debug ospf sr",
+DEFPY (debug_ospf_ti_lfa,
+ debug_ospf_ti_lfa_cmd,
+ "[no$no] debug ospf [(1-65535)$instance] ti-lfa",
NO_STR
DEBUG_STR
OSPF_STR
- "OSPF-SR information\n")
+ "Instance ID\n"
+ "OSPF-SR TI-LFA information\n")
{
- if (vty->node == CONFIG_NODE)
- CONF_DEBUG_OFF(sr, SR);
- TERM_DEBUG_OFF(sr, SR);
- return CMD_SUCCESS;
-}
+ if (instance && instance != ospf_instance)
+ return CMD_NOT_MY_INSTANCE;
-DEFUN(debug_ospf_ti_lfa, debug_ospf_ti_lfa_cmd, "debug ospf ti-lfa",
- DEBUG_STR OSPF_STR "OSPF-SR TI-LFA information\n")
-{
- if (vty->node == CONFIG_NODE)
- CONF_DEBUG_ON(ti_lfa, TI_LFA);
- TERM_DEBUG_ON(ti_lfa, TI_LFA);
- return CMD_SUCCESS;
-}
+ if (vty->node == CONFIG_NODE) {
+ if (no)
+ DEBUG_OFF(ti_lfa, TI_LFA);
+ else
+ DEBUG_ON(ti_lfa, TI_LFA);
+ } else {
+ if (no)
+ TERM_DEBUG_OFF(ti_lfa, TI_LFA);
+ else
+ TERM_DEBUG_ON(ti_lfa, TI_LFA);
+ }
-DEFUN(no_debug_ospf_ti_lfa, no_debug_ospf_ti_lfa_cmd, "no debug ospf ti-lfa",
- NO_STR DEBUG_STR OSPF_STR "OSPF-SR TI-LFA information\n")
-{
- if (vty->node == CONFIG_NODE)
- CONF_DEBUG_OFF(ti_lfa, TI_LFA);
- TERM_DEBUG_OFF(ti_lfa, TI_LFA);
return CMD_SUCCESS;
}
-DEFUN (debug_ospf_default_info,
+DEFPY (debug_ospf_default_info,
debug_ospf_default_info_cmd,
- "debug ospf default-information",
+ "[no$no] debug ospf [(1-65535)$instance] default-information",
+ NO_STR
DEBUG_STR
OSPF_STR
+ "Instance ID\n"
"OSPF default information\n")
{
- if (vty->node == CONFIG_NODE)
- CONF_DEBUG_ON(defaultinfo, DEFAULTINFO);
- TERM_DEBUG_ON(defaultinfo, DEFAULTINFO);
+ if (instance && instance != ospf_instance)
+ return CMD_NOT_MY_INSTANCE;
+
+ if (vty->node == CONFIG_NODE) {
+ if (no)
+ DEBUG_OFF(defaultinfo, DEFAULTINFO);
+ else
+ DEBUG_ON(defaultinfo, DEFAULTINFO);
+ } else {
+ if (no)
+ TERM_DEBUG_OFF(defaultinfo, DEFAULTINFO);
+ else
+ TERM_DEBUG_ON(defaultinfo, DEFAULTINFO);
+ }
+
return CMD_SUCCESS;
}
-DEFUN (no_debug_ospf_default_info,
- no_debug_ospf_default_info_cmd,
- "no debug ospf default-information",
+DEFPY (debug_ospf_ldp_sync,
+ debug_ospf_ldp_sync_cmd,
+ "[no$no] debug ospf [(1-65535)$instance] ldp-sync",
NO_STR
DEBUG_STR
OSPF_STR
- "OSPF default information\n")
-{
- if (vty->node == CONFIG_NODE)
- CONF_DEBUG_OFF(defaultinfo, DEFAULTINFO);
- TERM_DEBUG_OFF(defaultinfo, DEFAULTINFO);
- return CMD_SUCCESS;
-}
-
-DEFUN(debug_ospf_ldp_sync,
- debug_ospf_ldp_sync_cmd,
- "debug ospf ldp-sync",
- DEBUG_STR OSPF_STR
- "OSPF LDP-Sync information\n")
+ "Instance ID\n"
+ "OSPF LDP-Sync information\n")
{
- if (vty->node == CONFIG_NODE)
- CONF_DEBUG_ON(ldp_sync, LDP_SYNC);
- TERM_DEBUG_ON(ldp_sync, LDP_SYNC);
- return CMD_SUCCESS;
-}
+ if (instance && instance != ospf_instance)
+ return CMD_NOT_MY_INSTANCE;
-DEFUN(no_debug_ospf_ldp_sync,
- no_debug_ospf_ldp_sync_cmd,
- "no debug ospf ldp-sync",
- NO_STR
- DEBUG_STR
- OSPF_STR
- "OSPF LDP-Sync information\n")
-{
- if (vty->node == CONFIG_NODE)
- CONF_DEBUG_OFF(ldp_sync, LDP_SYNC);
- TERM_DEBUG_OFF(ldp_sync, LDP_SYNC);
+ if (vty->node == CONFIG_NODE) {
+ if (no)
+ DEBUG_OFF(ldp_sync, LDP_SYNC);
+ else
+ DEBUG_ON(ldp_sync, LDP_SYNC);
+ } else {
+ if (no)
+ TERM_DEBUG_OFF(ldp_sync, LDP_SYNC);
+ else
+ TERM_DEBUG_ON(ldp_sync, LDP_SYNC);
+ }
return CMD_SUCCESS;
}
-DEFPY(debug_ospf_gr, debug_ospf_gr_cmd, "[no$no] debug ospf graceful-restart",
- NO_STR DEBUG_STR OSPF_STR "OSPF Graceful Restart\n")
+DEFPY (debug_ospf_gr,
+ debug_ospf_gr_cmd,
+ "[no$no] debug ospf [(1-65535)$instance] graceful-restart",
+ NO_STR
+ DEBUG_STR
+ OSPF_STR
+ "Instance ID\n"
+ "OSPF Graceful Restart\n")
{
- if (vty->node == CONFIG_NODE)
- CONF_DEBUG_ON(gr, GR);
+ if (instance && instance != ospf_instance)
+ return CMD_NOT_MY_INSTANCE;
- if (!no)
- TERM_DEBUG_ON(gr, GR);
- else
+ if (vty->node == CONFIG_NODE) {
+ if (no)
+ CONF_DEBUG_OFF(gr, GR);
+ else
+ CONF_DEBUG_ON(gr, GR);
+ }
+
+ if (no)
TERM_DEBUG_OFF(gr, GR);
+ else
+ TERM_DEBUG_ON(gr, GR);
return CMD_SUCCESS;
}
-DEFPY(debug_ospf_bfd, debug_ospf_bfd_cmd,
- "[no] debug ospf bfd",
- NO_STR
- DEBUG_STR
- OSPF_STR
- "Bidirection Forwarding Detection\n")
+DEFPY (debug_ospf_bfd,
+ debug_ospf_bfd_cmd,
+ "[no] debug ospf [(1-65535)$instance] bfd",
+ NO_STR
+ DEBUG_STR
+ OSPF_STR
+ "Instance ID\n"
+ "Bidirection Forwarding Detection\n")
{
+ if (instance && instance != ospf_instance)
+ return CMD_NOT_MY_INSTANCE;
+
if (vty->node == CONFIG_NODE) {
if (no) {
bfd_protocol_integration_set_debug(false);
- CONF_DEBUG_OFF(bfd, BFD_LIB);
+ DEBUG_OFF(bfd, BFD_LIB);
} else {
bfd_protocol_integration_set_debug(true);
- CONF_DEBUG_ON(bfd, BFD_LIB);
+ DEBUG_ON(bfd, BFD_LIB);
}
+ } else {
+ if (no)
+ TERM_DEBUG_OFF(bfd, BFD_LIB);
+ else
+ TERM_DEBUG_ON(bfd, BFD_LIB);
}
- if (no)
- TERM_DEBUG_OFF(bfd, BFD_LIB);
- else
- TERM_DEBUG_ON(bfd, BFD_LIB);
-
return CMD_SUCCESS;
}
-DEFUN(debug_ospf_client_api,
- debug_ospf_client_api_cmd,
- "debug ospf client-api",
- DEBUG_STR OSPF_STR
- "OSPF client API information\n")
+DEFPY (debug_ospf_client_api,
+ debug_ospf_client_api_cmd,
+ "[no$no] debug ospf [(1-65535)$instance] client-api",
+ NO_STR
+ DEBUG_STR
+ OSPF_STR
+ "Instance ID\n"
+ "OSPF client API information\n")
{
- if (vty->node == CONFIG_NODE)
- CONF_DEBUG_ON(client_api, CLIENT_API);
- TERM_DEBUG_ON(client_api, CLIENT_API);
+ if (instance && instance != ospf_instance)
+ return CMD_NOT_MY_INSTANCE;
+
+ if (vty->node == CONFIG_NODE) {
+ if (no)
+ DEBUG_OFF(client_api, CLIENT_API);
+ else
+ DEBUG_ON(client_api, CLIENT_API);
+ } else {
+ if (no)
+ TERM_DEBUG_OFF(client_api, CLIENT_API);
+ else
+ TERM_DEBUG_ON(client_api, CLIENT_API);
+ }
+
return CMD_SUCCESS;
}
-DEFUN(no_debug_ospf_client_api,
- no_debug_ospf_client_api_cmd,
- "no debug ospf client-api",
- NO_STR
- DEBUG_STR
- OSPF_STR
- "OSPF client API information\n")
+DEFPY (debug_ospf_orr,
+ debug_ospf_orr_cmd,
+ "[no$no] debug ospf [(1-65535)$instance] orr",
+ NO_STR
+ DEBUG_STR
+ OSPF_STR
+ "Instance ID\n"
+ "OSPF ORR information\n")
{
- if (vty->node == CONFIG_NODE)
- CONF_DEBUG_OFF(client_api, CLIENT_API);
- TERM_DEBUG_OFF(client_api, CLIENT_API);
+ if (instance && instance != ospf_instance)
+ return CMD_NOT_MY_INSTANCE;
+
+ if (vty->node == CONFIG_NODE) {
+ if (no)
+ DEBUG_OFF(orr, ORR);
+ else
+ DEBUG_ON(orr, ORR);
+ } else {
+ if (no)
+ TERM_DEBUG_OFF(orr, ORR);
+ else
+ TERM_DEBUG_ON(orr, ORR);
+ }
return CMD_SUCCESS;
}
@@ -1691,6 +1670,8 @@ DEFUN (no_debug_ospf,
for (i = 0; i < 5; i++)
DEBUG_PACKET_OFF(i, flag);
+
+ DEBUG_OFF(orr, ORR);
}
for (i = 0; i < 5; i++)
@@ -1721,6 +1702,7 @@ DEFUN (no_debug_ospf,
TERM_DEBUG_OFF(ti_lfa, TI_LFA);
TERM_DEBUG_OFF(bfd, BFD_LIB);
TERM_DEBUG_OFF(client_api, CLIENT_API);
+ TERM_DEBUG_OFF(orr, ORR);
return CMD_SUCCESS;
}
@@ -1816,7 +1798,7 @@ static int show_debugging_ospf_common(struct vty *vty)
}
if (IS_DEBUG_OSPF(defaultinfo, DEFAULTINFO) == OSPF_DEBUG_DEFAULTINFO)
- vty_out(vty, "OSPF default information is on\n");
+ vty_out(vty, " OSPF default information is on\n");
/* Show debug status for NSSA. */
if (IS_DEBUG_OSPF(nssa, NSSA) == OSPF_DEBUG_NSSA)
@@ -1850,6 +1832,12 @@ static int show_debugging_ospf_common(struct vty *vty)
if (IS_DEBUG_OSPF(client_api, CLIENT_API) == OSPF_DEBUG_CLIENT_API)
vty_out(vty, " OSPF client-api debugging is on\n");
+ /* Show debug status for ORR. */
+ if (IS_DEBUG_OSPF(orr, ORR) == OSPF_DEBUG_ORR)
+ vty_out(vty, " OSPF ORR debugging is on\n");
+
+ vty_out(vty, "\n");
+
return CMD_SUCCESS;
}
@@ -1860,7 +1848,11 @@ DEFUN_NOSH (show_debugging_ospf,
DEBUG_STR
OSPF_STR)
{
- return show_debugging_ospf_common(vty);
+ show_debugging_ospf_common(vty);
+
+ cmd_show_lib_debugs(vty);
+
+ return CMD_SUCCESS;
}
DEFUN_NOSH (show_debugging_ospf_instance,
@@ -1878,7 +1870,11 @@ DEFUN_NOSH (show_debugging_ospf_instance,
if (instance != ospf_instance)
return CMD_NOT_MY_INSTANCE;
- return show_debugging_ospf_common(vty);
+ show_debugging_ospf_common(vty);
+
+ cmd_show_lib_debugs(vty);
+
+ return CMD_SUCCESS;
}
static int config_write_debug(struct vty *vty);
@@ -1978,7 +1974,7 @@ static int config_write_debug(struct vty *vty)
& (OSPF_DEBUG_SEND_RECV | OSPF_DEBUG_DETAIL);
if (r == (OSPF_DEBUG_SEND_RECV | OSPF_DEBUG_DETAIL)) {
vty_out(vty, "debug ospf%s packet all detail\n", str);
- return 1;
+ write = 1;
}
/* debug ospf packet all. */
@@ -1991,7 +1987,7 @@ static int config_write_debug(struct vty *vty)
if (conf_debug_ospf_packet[i] & OSPF_DEBUG_DETAIL)
vty_out(vty, "debug ospf%s packet %s detail\n",
str, type_str[i]);
- return 1;
+ write = 1;
}
/* debug ospf packet (hello|dd|ls-request|ls-update|ls-ack)
@@ -2047,6 +2043,19 @@ static int config_write_debug(struct vty *vty)
write = 1;
}
+ /* debug ospf default-information */
+ if (IS_CONF_DEBUG_OSPF(defaultinfo, DEFAULTINFO) ==
+ OSPF_DEBUG_DEFAULTINFO) {
+ vty_out(vty, "debug ospf%s default-information\n", str);
+ write = 1;
+ }
+
+ /* debug ospf orr */
+ if (IS_CONF_DEBUG_OSPF(orr, ORR) == OSPF_DEBUG_ORR) {
+ vty_out(vty, "debug ospf%s orr\n", str);
+ write = 1;
+ }
+
return write;
}
@@ -2068,24 +2077,18 @@ void ospf_debug_init(void)
install_element(ENABLE_NODE, &debug_ospf_default_info_cmd);
install_element(ENABLE_NODE, &debug_ospf_ldp_sync_cmd);
install_element(ENABLE_NODE, &debug_ospf_client_api_cmd);
+ install_element(ENABLE_NODE, &debug_ospf_orr_cmd);
install_element(ENABLE_NODE, &no_debug_ospf_ism_cmd);
install_element(ENABLE_NODE, &no_debug_ospf_nsm_cmd);
install_element(ENABLE_NODE, &no_debug_ospf_lsa_cmd);
install_element(ENABLE_NODE, &no_debug_ospf_zebra_cmd);
install_element(ENABLE_NODE, &no_debug_ospf_event_cmd);
install_element(ENABLE_NODE, &no_debug_ospf_nssa_cmd);
- install_element(ENABLE_NODE, &no_debug_ospf_te_cmd);
- install_element(ENABLE_NODE, &no_debug_ospf_sr_cmd);
- install_element(ENABLE_NODE, &no_debug_ospf_ti_lfa_cmd);
- install_element(ENABLE_NODE, &no_debug_ospf_default_info_cmd);
- install_element(ENABLE_NODE, &no_debug_ospf_ldp_sync_cmd);
- install_element(ENABLE_NODE, &no_debug_ospf_client_api_cmd);
install_element(ENABLE_NODE, &debug_ospf_gr_cmd);
install_element(ENABLE_NODE, &debug_ospf_bfd_cmd);
install_element(ENABLE_NODE, &show_debugging_ospf_instance_cmd);
install_element(ENABLE_NODE, &debug_ospf_packet_cmd);
- install_element(ENABLE_NODE, &no_debug_ospf_packet_cmd);
install_element(ENABLE_NODE, &debug_ospf_instance_nsm_cmd);
install_element(ENABLE_NODE, &debug_ospf_instance_lsa_cmd);
@@ -2100,7 +2103,6 @@ void ospf_debug_init(void)
install_element(ENABLE_NODE, &no_debug_ospf_cmd);
install_element(CONFIG_NODE, &debug_ospf_packet_cmd);
- install_element(CONFIG_NODE, &no_debug_ospf_packet_cmd);
install_element(CONFIG_NODE, &debug_ospf_ism_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_ism_cmd);
@@ -2115,17 +2117,12 @@ void ospf_debug_init(void)
install_element(CONFIG_NODE, &debug_ospf_default_info_cmd);
install_element(CONFIG_NODE, &debug_ospf_ldp_sync_cmd);
install_element(CONFIG_NODE, &debug_ospf_client_api_cmd);
+ install_element(CONFIG_NODE, &debug_ospf_orr_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_nsm_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_lsa_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_zebra_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_event_cmd);
install_element(CONFIG_NODE, &no_debug_ospf_nssa_cmd);
- install_element(CONFIG_NODE, &no_debug_ospf_te_cmd);
- install_element(CONFIG_NODE, &no_debug_ospf_sr_cmd);
- install_element(CONFIG_NODE, &no_debug_ospf_ti_lfa_cmd);
- install_element(CONFIG_NODE, &no_debug_ospf_default_info_cmd);
- install_element(CONFIG_NODE, &no_debug_ospf_ldp_sync_cmd);
- install_element(CONFIG_NODE, &no_debug_ospf_client_api_cmd);
install_element(CONFIG_NODE, &debug_ospf_gr_cmd);
install_element(CONFIG_NODE, &debug_ospf_bfd_cmd);
diff --git a/ospfd/ospf_dump.h b/ospfd/ospf_dump.h
index 251be7c8d..e9ba8fc79 100644
--- a/ospfd/ospf_dump.h
+++ b/ospfd/ospf_dump.h
@@ -70,6 +70,8 @@
#define OSPF_DEBUG_CLIENT_API 0x01
+#define OSPF_DEBUG_ORR 0x01
+
/* Macro for setting debug option. */
#define CONF_DEBUG_PACKET_ON(a, b) conf_debug_ospf_packet[a] |= (b)
#define CONF_DEBUG_PACKET_OFF(a, b) conf_debug_ospf_packet[a] &= ~(b)
@@ -129,6 +131,8 @@
#define AREA_NAME(A) ospf_area_name_string ((A))
#define IF_NAME(I) ospf_if_name_string ((I))
+#define IS_DEBUG_OSPF_ORR IS_DEBUG_OSPF(orr, ORR)
+
/* Extern debug flag. */
extern unsigned long term_debug_ospf_packet[];
extern unsigned long term_debug_ospf_event;
@@ -146,6 +150,7 @@ extern unsigned long term_debug_ospf_ldp_sync;
extern unsigned long term_debug_ospf_gr;
extern unsigned long term_debug_ospf_bfd;
extern unsigned long term_debug_ospf_client_api;
+extern unsigned long term_debug_ospf_orr;
/* Message Strings. */
extern char *ospf_lsa_type_str[];
diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c
index e686a93ba..4bbeee2d7 100644
--- a/ospfd/ospf_flood.c
+++ b/ospfd/ospf_flood.c
@@ -648,6 +648,13 @@ int ospf_flood_through_interface(struct ospf_interface *oi,
OSPF_SEND_PACKET_DIRECT);
}
} else
+ /* Optimization: for P2MP interfaces,
+ don't send back out the incoming interface immediately,
+ allow time to rx multicast ack to the rx'ed (multicast)
+ update */
+ if (retx_flag != 1 ||
+ oi->type != OSPF_IFTYPE_POINTOMULTIPOINT || inbr == NULL ||
+ oi != inbr->oi)
ospf_ls_upd_send_lsa(oi->nbr_self, lsa,
OSPF_SEND_PACKET_INDIRECT);
@@ -811,6 +818,11 @@ int ospf_flood_through(struct ospf *ospf, struct ospf_neighbor *inbr,
break;
}
+ /* always need to send ack when incoming intf is PTP or P2MP */
+ if (inbr != NULL && (inbr->oi->type == OSPF_IFTYPE_POINTOMULTIPOINT ||
+ inbr->oi->type == OSPF_IFTYPE_POINTOPOINT))
+ lsa_ack_flag = 1;
+
return (lsa_ack_flag);
}
diff --git a/ospfd/ospf_gr.c b/ospfd/ospf_gr.c
index 66ef1d656..6678d8c1f 100644
--- a/ospfd/ospf_gr.c
+++ b/ospfd/ospf_gr.c
@@ -44,9 +44,7 @@
#include "ospfd/ospf_gr.h"
#include "ospfd/ospf_errors.h"
#include "ospfd/ospf_dump.h"
-#ifndef VTYSH_EXTRACT_PL
#include "ospfd/ospf_gr_clippy.c"
-#endif
static void ospf_gr_nvm_delete(struct ospf *ospf);
diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c
index 646d31836..a0b14e73e 100644
--- a/ospfd/ospf_interface.c
+++ b/ospfd/ospf_interface.c
@@ -461,13 +461,13 @@ struct ospf_interface *ospf_if_lookup_recv_if(struct ospf *ospf,
{
struct route_node *rn;
struct prefix_ipv4 addr;
- struct ospf_interface *oi, *match;
+ struct ospf_interface *oi, *match, *unnumbered_match;
addr.family = AF_INET;
addr.prefix = src;
addr.prefixlen = IPV4_MAX_BITLEN;
- match = NULL;
+ match = unnumbered_match = NULL;
for (rn = route_top(IF_OIFS(ifp)); rn; rn = route_next(rn)) {
oi = rn->info;
@@ -482,7 +482,7 @@ struct ospf_interface *ospf_if_lookup_recv_if(struct ospf *ospf,
continue;
if (CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED))
- match = oi;
+ unnumbered_match = oi;
else if (prefix_match(CONNECTED_PREFIX(oi->connected),
(struct prefix *)&addr)) {
if ((match == NULL) || (match->address->prefixlen
@@ -491,7 +491,10 @@ struct ospf_interface *ospf_if_lookup_recv_if(struct ospf *ospf,
}
}
- return match;
+ if (match)
+ return match;
+
+ return unnumbered_match;
}
void ospf_interface_fifo_flush(struct ospf_interface *oi)
diff --git a/ospfd/ospf_ldp_sync.c b/ospfd/ospf_ldp_sync.c
index 77e96f173..7b1fa6626 100644
--- a/ospfd/ospf_ldp_sync.c
+++ b/ospfd/ospf_ldp_sync.c
@@ -751,9 +751,7 @@ void ospf_ldp_sync_if_write_config(struct vty *vty,
/*
* LDP-SYNC commands.
*/
-#ifndef VTYSH_EXTRACT_PL
#include "ospfd/ospf_ldp_sync_clippy.c"
-#endif
DEFPY (ospf_mpls_ldp_sync,
ospf_mpls_ldp_sync_cmd,
diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c
index 0df0072f6..a67b6c6c1 100644
--- a/ospfd/ospf_lsa.c
+++ b/ospfd/ospf_lsa.c
@@ -52,6 +52,8 @@
#include "ospfd/ospf_zebra.h"
#include "ospfd/ospf_abr.h"
#include "ospfd/ospf_errors.h"
+#include "ospfd/ospf_te.h"
+#include "ospfd/ospf_orr.h"
static struct ospf_lsa *ospf_handle_summarylsa_lsId_chg(struct ospf *ospf,
struct prefix_ipv4 *p,
@@ -188,6 +190,7 @@ struct ospf_lsa *ospf_lsa_new(void)
new->refresh_list = -1;
new->vrf_id = VRF_DEFAULT;
new->to_be_acknowledged = 0;
+ new->opaque_zero_len_delete = 0;
return new;
}
@@ -2202,7 +2205,7 @@ struct ospf_lsa *ospf_external_lsa_originate(struct ospf *ospf,
*/
if (ospf->router_id.s_addr == INADDR_ANY) {
- if (IS_DEBUG_OSPF_EVENT)
+ if (ei && IS_DEBUG_OSPF_EVENT)
zlog_debug(
"LSA[Type5:%pI4]: deferring AS-external-LSA origination, router ID is zero",
&ei->p.prefix);
@@ -2211,7 +2214,7 @@ struct ospf_lsa *ospf_external_lsa_originate(struct ospf *ospf,
/* Create new AS-external-LSA instance. */
if ((new = ospf_external_lsa_new(ospf, ei, NULL)) == NULL) {
- if (IS_DEBUG_OSPF_EVENT)
+ if (ei && IS_DEBUG_OSPF_EVENT)
zlog_debug(
"LSA[Type5:%pI4]: Could not originate AS-external-LSA",
&ei->p.prefix);
@@ -2640,6 +2643,13 @@ ospf_router_lsa_install(struct ospf *ospf, struct ospf_lsa *new, int rt_recalc)
ospf_refresher_register_lsa(ospf, new);
}
+ /* For BGP ORR SPF should be calculated from specified root(s) */
+ else if (ospf->orr_spf_request) {
+ ospf_lsa_unlock(&area->router_lsa_rcvd);
+ area->router_lsa_rcvd = ospf_lsa_lock(new);
+ ospf_orr_root_update_rcvd_lsa(area->router_lsa_rcvd);
+ }
+
if (rt_recalc)
ospf_spf_calculate_schedule(ospf, SPF_FLAG_ROUTER_LSA_INSTALL);
return new;
@@ -2651,7 +2661,6 @@ static struct ospf_lsa *ospf_network_lsa_install(struct ospf *ospf,
struct ospf_lsa *new,
int rt_recalc)
{
-
/* RFC 2328 Section 13.2 Router-LSAs and network-LSAs
The entire routing table must be recalculated, starting with
the shortest path calculations for each area (not just the
@@ -3400,6 +3409,82 @@ struct ospf_lsa *ospf_lsa_lookup_by_id(struct ospf_area *area, uint32_t type,
return NULL;
}
+struct ospf_lsa *ospf_lsa_lookup_by_adv_rid(struct ospf_area *area,
+ uint32_t type, struct in_addr id)
+{
+ struct ospf_lsa *lsa = NULL;
+ struct route_node *rn = NULL;
+
+ switch (type) {
+ case OSPF_ROUTER_LSA:
+ for (rn = route_top(ROUTER_LSDB(area)); rn;
+ rn = route_next(rn)) {
+ lsa = rn->info;
+ if (lsa) {
+ if (IPV4_ADDR_SAME(&lsa->data->adv_router,
+ &id)) {
+ route_unlock_node(rn);
+ return lsa;
+ }
+ }
+ }
+ break;
+ case OSPF_NETWORK_LSA:
+ case OSPF_SUMMARY_LSA:
+ case OSPF_ASBR_SUMMARY_LSA:
+ case OSPF_AS_EXTERNAL_LSA:
+ case OSPF_AS_NSSA_LSA:
+ case OSPF_OPAQUE_LINK_LSA:
+ case OSPF_OPAQUE_AREA_LSA:
+ case OSPF_OPAQUE_AS_LSA:
+ /* Currently not used. */
+ break;
+ default:
+ break;
+ }
+
+ return NULL;
+}
+
+struct ospf_lsa *ospf_lsa_lookup_by_mpls_te_rid(struct ospf_area *area,
+ uint32_t type,
+ struct in_addr id)
+{
+ struct ospf_lsa *lsa = NULL;
+ struct route_node *rn = NULL;
+ struct lsa_header *lsah = NULL;
+ uint32_t lsid;
+ uint8_t opaque_type;
+ struct tlv_header *tlvh = NULL;
+ struct te_tlv_router_addr *router_addr = NULL;
+
+ if (type != OSPF_OPAQUE_AREA_LSA)
+ return NULL;
+
+ for (rn = route_top(OPAQUE_AREA_LSDB(area)); rn; rn = route_next(rn)) {
+ lsa = rn->info;
+ if (lsa) {
+ lsah = lsa->data;
+ lsid = ntohl(lsah->id.s_addr);
+ opaque_type = GET_OPAQUE_TYPE(lsid);
+ if (opaque_type != OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA)
+ continue;
+
+ tlvh = TLV_HDR_TOP(lsah);
+ if (!tlvh ||
+ (ntohs(tlvh->type) != TE_TLV_ROUTER_ADDR) ||
+ (ntohs(tlvh->length) != TE_LINK_SUBTLV_DEF_SIZE))
+ continue;
+ router_addr = (struct te_tlv_router_addr *)tlvh;
+ if (IPV4_ADDR_SAME(&router_addr->value, &id)) {
+ route_unlock_node(rn);
+ return lsa;
+ }
+ }
+ }
+ return NULL;
+}
+
struct ospf_lsa *ospf_lsa_lookup_by_header(struct ospf_area *area,
struct lsa_header *lsah)
{
@@ -3512,7 +3597,8 @@ int ospf_lsa_different(struct ospf_lsa *l1, struct ospf_lsa *l2,
&& CHECK_FLAG((l1->flags ^ l2->flags), OSPF_LSA_RECEIVED))
return 1; /* May be a stale LSA in the LSBD */
- assert(l1->size > OSPF_LSA_HEADER_SIZE);
+ if (l1->size == OSPF_LSA_HEADER_SIZE)
+ return 0; /* nothing to compare */
p1 = (char *)l1->data;
p2 = (char *)l2->data;
@@ -3823,8 +3909,9 @@ struct ospf_lsa *ospf_lsa_refresh(struct ospf *ospf, struct ospf_lsa *lsa)
struct as_external_lsa *al;
struct prefix_ipv4 p;
- assert(CHECK_FLAG(lsa->flags, OSPF_LSA_SELF));
- assert(IS_LSA_SELF(lsa));
+ if (!CHECK_FLAG(lsa->flags, OSPF_LSA_SELF) && !IS_LSA_SELF(lsa) &&
+ !IS_LSA_ORR(lsa))
+ return NULL;
assert(lsa->lock > 0);
switch (lsa->data->type) {
@@ -3894,7 +3981,8 @@ void ospf_refresher_register_lsa(struct ospf *ospf, struct ospf_lsa *lsa)
uint16_t index, current_index;
assert(lsa->lock > 0);
- assert(IS_LSA_SELF(lsa));
+ if (!IS_LSA_SELF(lsa) && !IS_LSA_ORR(lsa))
+ return;
if (lsa->refresh_list < 0) {
int delay;
@@ -3943,7 +4031,8 @@ void ospf_refresher_register_lsa(struct ospf *ospf, struct ospf_lsa *lsa)
void ospf_refresher_unregister_lsa(struct ospf *ospf, struct ospf_lsa *lsa)
{
assert(lsa->lock > 0);
- assert(IS_LSA_SELF(lsa));
+ if (!IS_LSA_SELF(lsa) || !IS_LSA_ORR(lsa))
+ return;
if (lsa->refresh_list >= 0) {
struct list *refresh_list =
ospf->lsa_refresh_queue.qs[lsa->refresh_list];
diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h
index 97c15d1e3..4e884fa89 100644
--- a/ospfd/ospf_lsa.h
+++ b/ospfd/ospf_lsa.h
@@ -74,15 +74,16 @@ struct vertex;
/* OSPF LSA. */
struct ospf_lsa {
/* LSA origination flag. */
- uint8_t flags;
-#define OSPF_LSA_SELF 0x01
-#define OSPF_LSA_SELF_CHECKED 0x02
-#define OSPF_LSA_RECEIVED 0x04
-#define OSPF_LSA_APPROVED 0x08
-#define OSPF_LSA_DISCARD 0x10
-#define OSPF_LSA_LOCAL_XLT 0x20
-#define OSPF_LSA_PREMATURE_AGE 0x40
-#define OSPF_LSA_IN_MAXAGE 0x80
+ uint16_t flags;
+#define OSPF_LSA_SELF 0x0001
+#define OSPF_LSA_SELF_CHECKED 0x0002
+#define OSPF_LSA_RECEIVED 0x0004
+#define OSPF_LSA_APPROVED 0x0008
+#define OSPF_LSA_DISCARD 0x0010
+#define OSPF_LSA_LOCAL_XLT 0x0020
+#define OSPF_LSA_PREMATURE_AGE 0x0040
+#define OSPF_LSA_IN_MAXAGE 0x0080
+#define OSPF_LSA_ORR 0x0100
/* LSA data. and size */
struct lsa_header *data;
@@ -123,6 +124,9 @@ struct ospf_lsa {
/*For topo chg detection in HELPER role*/
bool to_be_acknowledged;
+
+ /* send maxage with no data */
+ bool opaque_zero_len_delete;
};
/* OSPF LSA Link Type. */
@@ -222,6 +226,7 @@ enum lsid_status { LSID_AVAILABLE = 0, LSID_CHANGE, LSID_NOT_AVAILABLE };
#define IS_LSA_MAXAGE(L) (LS_AGE ((L)) == OSPF_LSA_MAXAGE)
#define IS_LSA_MAX_SEQ(L) \
((L)->data->ls_seqnum == htonl(OSPF_MAX_SEQUENCE_NUMBER))
+#define IS_LSA_ORR(L) (CHECK_FLAG ((L)->flags, OSPF_LSA_ORR))
#define OSPF_LSA_UPDATE_DELAY 2
@@ -292,6 +297,12 @@ extern struct ospf_lsa *ospf_lsa_lookup(struct ospf *ospf, struct ospf_area *,
struct in_addr);
extern struct ospf_lsa *ospf_lsa_lookup_by_id(struct ospf_area *, uint32_t,
struct in_addr);
+extern struct ospf_lsa *ospf_lsa_lookup_by_adv_rid(struct ospf_area *area,
+ uint32_t type,
+ struct in_addr id);
+extern struct ospf_lsa *ospf_lsa_lookup_by_mpls_te_rid(struct ospf_area *area,
+ uint32_t type,
+ struct in_addr id);
extern struct ospf_lsa *ospf_lsa_lookup_by_header(struct ospf_area *,
struct lsa_header *);
extern int ospf_lsa_more_recent(struct ospf_lsa *, struct ospf_lsa *);
diff --git a/ospfd/ospf_lsdb.c b/ospfd/ospf_lsdb.c
index f4fb858a5..3c65ac388 100644
--- a/ospfd/ospf_lsdb.c
+++ b/ospfd/ospf_lsdb.c
@@ -30,6 +30,7 @@
#include "ospfd/ospf_asbr.h"
#include "ospfd/ospf_lsa.h"
#include "ospfd/ospf_lsdb.h"
+#include "ospfd/ospf_orr.h"
struct ospf_lsdb *ospf_lsdb_new(void)
{
@@ -87,6 +88,10 @@ static void ospf_lsdb_delete_entry(struct ospf_lsdb *lsdb,
assert(rn->table == lsdb->type[lsa->data->type].db);
+ /* Update ORR Root table MPLS-TE Router address's advertise router */
+ if (lsa->data->type == OSPF_OPAQUE_AREA_LSA)
+ ospf_orr_root_table_update(lsa, false);
+
if (IS_LSA_SELF(lsa))
lsdb->type[lsa->data->type].count_self--;
lsdb->type[lsa->data->type].count--;
@@ -134,6 +139,10 @@ void ospf_lsdb_add(struct ospf_lsdb *lsdb, struct ospf_lsa *lsa)
#endif /* MONITOR_LSDB_CHANGE */
lsdb->type[lsa->data->type].checksum += ntohs(lsa->data->checksum);
rn->info = ospf_lsa_lock(lsa); /* lsdb */
+
+ /* Update ORR Root table MPLS-TE Router address's advertise router */
+ if (lsa->data->type == OSPF_OPAQUE_AREA_LSA)
+ ospf_orr_root_table_update(lsa, true);
}
void ospf_lsdb_delete(struct ospf_lsdb *lsdb, struct ospf_lsa *lsa)
diff --git a/ospfd/ospf_memory.c b/ospfd/ospf_memory.c
index 283844389..5577a291b 100644
--- a/ospfd/ospf_memory.c
+++ b/ospfd/ospf_memory.c
@@ -60,3 +60,4 @@ DEFINE_MTYPE(OSPFD, OSPF_GR_HELPER, "OSPF Graceful Restart Helper");
DEFINE_MTYPE(OSPFD, OSPF_EXTERNAL_RT_AGGR, "OSPF External Route Summarisation");
DEFINE_MTYPE(OSPFD, OSPF_P_SPACE, "OSPF TI-LFA P-Space");
DEFINE_MTYPE(OSPFD, OSPF_Q_SPACE, "OSPF TI-LFA Q-Space");
+DEFINE_MTYPE(OSPFD, OSPF_ORR_ROOT, "OSPF ORR Root");
diff --git a/ospfd/ospf_memory.h b/ospfd/ospf_memory.h
index 9bd0a844a..3d2133b11 100644
--- a/ospfd/ospf_memory.h
+++ b/ospfd/ospf_memory.h
@@ -59,5 +59,6 @@ DECLARE_MTYPE(OSPF_GR_HELPER);
DECLARE_MTYPE(OSPF_EXTERNAL_RT_AGGR);
DECLARE_MTYPE(OSPF_P_SPACE);
DECLARE_MTYPE(OSPF_Q_SPACE);
+DECLARE_MTYPE(OSPF_ORR_ROOT);
#endif /* _QUAGGA_OSPF_MEMORY_H */
diff --git a/ospfd/ospf_opaque.c b/ospfd/ospf_opaque.c
index 261d69df3..ab647625f 100644
--- a/ospfd/ospf_opaque.c
+++ b/ospfd/ospf_opaque.c
@@ -2050,6 +2050,17 @@ void ospf_opaque_lsa_flush_schedule(struct ospf_lsa *lsa0)
goto out;
}
+ if (lsa->opaque_zero_len_delete &&
+ lsa->data->length != htons(sizeof(struct lsa_header))) {
+ /* minimize the size of the withdrawal: */
+ /* increment the sequence number and make len just header */
+ /* and update checksum */
+ lsa->data->ls_seqnum = lsa_seqnum_increment(lsa);
+ lsa->data->length = htons(sizeof(struct lsa_header));
+ lsa->data->checksum = 0;
+ lsa->data->checksum = ospf_lsa_checksum(lsa->data);
+ }
+
/* Delete this lsa from neighbor retransmit-list. */
switch (lsa->data->type) {
case OSPF_OPAQUE_LINK_LSA:
diff --git a/ospfd/ospf_opaque.h b/ospfd/ospf_opaque.h
index 9c7687790..05fe6deac 100644
--- a/ospfd/ospf_opaque.h
+++ b/ospfd/ospf_opaque.h
@@ -77,7 +77,7 @@
#define OPAQUE_TYPE_RANGE_RESERVED(type) (127 < (type) && (type) <= 255)
-#define OSPF_OPAQUE_LSA_MIN_SIZE 4U
+#define OSPF_OPAQUE_LSA_MIN_SIZE 0 /* RFC5250 imposes no minimum */
#define VALID_OPAQUE_INFO_LEN(lsahdr) \
((ntohs((lsahdr)->length) >= sizeof(struct lsa_header)) \
diff --git a/ospfd/ospf_orr.c b/ospfd/ospf_orr.c
new file mode 100644
index 000000000..eed948b19
--- /dev/null
+++ b/ospfd/ospf_orr.c
@@ -0,0 +1,594 @@
+/*
+ * OSPF BGP-IGP IGP metric update handling routines
+ * Copyright (C) 2021 Samsung R&D Institute India - Bangalore.
+ * Madhurilatha Kuruganti
+ *
+ * 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 <string.h>
+
+#include "monotime.h"
+#include "memory.h"
+#include "thread.h"
+#include "prefix.h"
+#include "table.h"
+#include "vty.h"
+#include "command.h"
+#include "plist.h"
+#include "log.h"
+#include "zclient.h"
+#include <lib/json.h>
+#include "defaults.h"
+#include "orr_msg.h"
+
+#include "ospfd.h"
+#include "ospf_asbr.h"
+#include "ospf_dump.h"
+#include "ospf_lsa.h"
+#include "ospf_orr.h"
+#include "ospf_route.h"
+#include "ospf_spf.h"
+#include "ospf_te.h"
+
+static void ospf_show_orr_root(struct orr_root *root);
+static void ospf_show_orr(struct ospf *ospf, afi_t afi, safi_t safi);
+static struct orr_root *ospf_orr_root_new(struct ospf *ospf, afi_t afi,
+ safi_t safi, struct prefix *p,
+ char *group_name)
+{
+ struct list *orr_root_list = NULL;
+ struct orr_root *root = NULL;
+
+ if (!ospf->orr_root[afi][safi])
+ ospf->orr_root[afi][safi] = list_new();
+
+ orr_root_list = ospf->orr_root[afi][safi];
+ root = XCALLOC(MTYPE_OSPF_ORR_ROOT, sizeof(struct orr_root));
+
+ listnode_add(orr_root_list, root);
+
+ root->afi = afi;
+ root->safi = safi;
+ prefix_copy(&root->prefix, p);
+ IPV4_ADDR_COPY(&root->router_id, &p->u.prefix4);
+ strlcpy(root->group_name, group_name, sizeof(root->group_name));
+ root->new_rtrs = NULL;
+ root->new_table = NULL;
+
+ ospf_orr_debug(
+ "%s: For %s %s, ORR Group %s, created ORR Root entry %pFX.",
+ __func__, afi2str(afi), safi2str(safi), root->group_name, p);
+
+ return root;
+}
+
+static struct orr_root *ospf_orr_root_lookup(struct ospf *ospf, afi_t afi,
+ safi_t safi, struct in_addr *rid)
+{
+ struct list *orr_root_list = NULL;
+ struct orr_root *root = NULL;
+ struct listnode *node;
+
+ orr_root_list = ospf->orr_root[afi][safi];
+ if (!orr_root_list)
+ return NULL;
+
+ for (ALL_LIST_ELEMENTS_RO(orr_root_list, node, root))
+ if (IPV4_ADDR_SAME(&root->router_id, rid))
+ return root;
+
+ ospf_orr_debug("%s: For %s %s, ORR Root '%pI4' not found.", __func__,
+ afi2str(afi), safi2str(safi), rid);
+
+ return NULL;
+}
+
+static struct orr_root *ospf_orr_root_lookup_by_adv_rid(struct ospf *ospf,
+ afi_t afi, safi_t safi,
+ struct in_addr *rid)
+{
+ struct list *orr_root_list = NULL;
+ struct orr_root *root = NULL;
+ struct listnode *node;
+
+ orr_root_list = ospf->orr_root[afi][safi];
+ if (!orr_root_list)
+ return NULL;
+
+ for (ALL_LIST_ELEMENTS_RO(orr_root_list, node, root))
+ if (IPV4_ADDR_SAME(&root->adv_router, rid))
+ return root;
+
+ return NULL;
+}
+
+/*
+ * Lookup each area's LSDB if is there is any opaque area LSA received and
+ * update the root database with the advertising router.
+ */
+static struct ospf_lsa *
+ospf_orr_lookup_opaque_area_lsa_by_id(struct in_addr rid)
+{
+ struct ospf_lsa *lsa = NULL;
+ struct ospf_area *area = NULL;
+ struct ospf *ospf = NULL;
+ struct listnode *node = NULL, *nnode = NULL;
+
+ /* if ospf is not enabled ignore */
+ ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
+ if (!ospf)
+ return NULL;
+
+ /* Lookup for Opaque area LSA in each area. */
+ for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area)) {
+ lsa = ospf_lsa_lookup_by_mpls_te_rid(area, OSPF_OPAQUE_AREA_LSA,
+ rid);
+ if (!lsa)
+ continue;
+ ospf_orr_debug(
+ "%s: Opaque Area LSA found in area %pI4 for %pI4",
+ __func__, &area->area_id, &rid);
+ return lsa;
+ }
+ return NULL;
+}
+
+/*
+ * Lookup each area's LSDB if is there is any opaque area LSA received and
+ * update the root database with the advertising router.
+ */
+static struct ospf_lsa *ospf_orr_lookup_router_lsa_by_id(struct in_addr rid)
+{
+ struct ospf_lsa *lsa = NULL;
+ struct ospf_area *area = NULL;
+ struct ospf *ospf = NULL;
+ struct listnode *node = NULL, *nnode = NULL;
+
+ /* if ospf is not enabled ignore */
+ ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
+ if (!ospf)
+ return NULL;
+
+ /* Lookup for Router LSA in each area. */
+ for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area)) {
+ lsa = ospf_lsa_lookup_by_adv_rid(area, OSPF_ROUTER_LSA, rid);
+ if (!lsa)
+ continue;
+ ospf_orr_debug("%s: Router LSA found in area %pI4 for %pI4",
+ __func__, &area->area_id, &rid);
+ return lsa;
+ }
+ return NULL;
+}
+
+/*
+ * BGP-IGP IGP metric msg between BGP and IGP
+ */
+int ospf_orr_igp_metric_register(struct orr_igp_metric_reg msg)
+{
+ afi_t afi;
+ safi_t safi;
+ struct ospf *ospf = NULL;
+ struct ospf_lsa *lsa = NULL;
+ struct orr_root *root = NULL;
+
+ /* if ospf is not enabled ignore */
+ ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
+ if (!ospf)
+ return -1;
+
+ if (msg.proto != ZEBRA_ROUTE_BGP)
+ return -1;
+
+ afi = family2afi(msg.prefix.family);
+ safi = msg.safi;
+
+ ospf_orr_debug(
+ "%s: Received IGP metric %s message from BGP for ORR Group %s from location %pFX",
+ __func__, msg.reg ? "Register" : "Unregister", msg.group_name,
+ &msg.prefix);
+
+ /* Get ORR Root entry for the given address-family */
+ root = ospf_orr_root_lookup(ospf, afi, safi, &msg.prefix.u.prefix4);
+
+ /* Should not hit this condition */
+ if ((root && msg.reg) || (!root && !msg.reg))
+ return -1;
+
+ /* Create ORR Root entry and calculate SPF from root */
+ if (!root) {
+ root = ospf_orr_root_new(ospf, afi, safi, &msg.prefix,
+ msg.group_name);
+ if (!root) {
+ ospf_orr_debug(
+ "%s: For %s %s, Failed to create ORR Root entry %pFX.",
+ __func__, afi2str(afi), safi2str(safi),
+ &msg.prefix);
+ return -1;
+ }
+ ospf->orr_spf_request++;
+
+ lsa = ospf_orr_lookup_opaque_area_lsa_by_id(root->router_id);
+ if (!lsa || !lsa->data)
+ return -1;
+
+ IPV4_ADDR_COPY(&root->adv_router, &lsa->data->adv_router);
+
+ /* Lookup LSDB for Router LSA */
+ if (!root->router_lsa_rcvd) {
+ lsa = ospf_orr_lookup_router_lsa_by_id(
+ root->adv_router);
+ if (!lsa || !lsa->data)
+ return -1;
+ root->router_lsa_rcvd = lsa;
+ }
+
+ /* Compute SPF for all root nodes */
+ ospf_orr_spf_calculate_schedule(ospf);
+ }
+ /* Delete ORR Root entry. SPF calculation not required. */
+ else {
+ listnode_delete(ospf->orr_root[afi][safi], root);
+ XFREE(MTYPE_OSPF_ORR_ROOT, root);
+
+ /* If last node is deleted in the list */
+ if (!ospf->orr_root[afi][safi]->count)
+ list_delete(&ospf->orr_root[afi][safi]);
+
+ ospf->orr_spf_request--;
+ }
+
+ if (IS_DEBUG_OSPF_ORR)
+ ospf_show_orr(ospf, afi, safi);
+
+ return 0;
+}
+
+void ospf_orr_igp_metric_send_update_add(struct orr_root *root,
+ unsigned short instance)
+{
+ int ret;
+ uint8_t count = 0;
+ struct route_node *rn;
+ struct ospf_route *or;
+ struct orr_igp_metric_info msg;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.proto = ZEBRA_ROUTE_OSPF;
+ msg.safi = root->safi;
+ msg.instId = instance;
+ msg.add = true;
+ prefix_copy(&msg.root, &root->prefix);
+
+ /* Update prefix table from ORR Route table */
+ for (rn = route_top(root->new_table); rn; rn = route_next(rn)) {
+ or = rn->info;
+ if (!or)
+ continue;
+
+ if (or->type != OSPF_DESTINATION_NETWORK &&
+ or->type != OSPF_DESTINATION_DISCARD)
+ continue;
+
+ if (ospf_route_match_same(root->old_table,
+ (struct prefix_ipv4 *)&rn->p, or))
+ continue;
+
+ if (count < ORR_MAX_PREFIX) {
+ prefix_copy(&msg.nexthop[count].prefix,
+ (struct prefix_ipv4 *)&rn->p);
+ msg.nexthop[count].metric = or->cost;
+ count++;
+ } else {
+ msg.num_entries = count;
+ ret = zclient_send_opaque(zclient,
+ ORR_IGP_METRIC_UPDATE,
+ (uint8_t *)&msg, sizeof(msg));
+ if (ret != ZCLIENT_SEND_SUCCESS)
+ ospf_orr_debug(
+ "%s: Failed to send message to BGP.",
+ __func__);
+ count = 0;
+ prefix_copy(&msg.nexthop[count].prefix,
+ (struct prefix_ipv4 *)&rn->p);
+ msg.nexthop[count].metric = or->cost;
+ count++;
+ }
+ }
+ if (count > 0 && count <= ORR_MAX_PREFIX) {
+ msg.num_entries = count;
+ ret = zclient_send_opaque(zclient, ORR_IGP_METRIC_UPDATE,
+ (uint8_t *)&msg, sizeof(msg));
+ if (ret != ZCLIENT_SEND_SUCCESS)
+ ospf_orr_debug("%s: Failed to send message to BGP.",
+ __func__);
+ }
+}
+
+void ospf_orr_igp_metric_send_update_delete(struct orr_root *root,
+ unsigned short instance)
+{
+ int ret;
+ uint8_t count = 0;
+ struct route_node *rn;
+ struct ospf_route *or;
+ struct orr_igp_metric_info msg;
+
+ if (!root->old_table)
+ return;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.proto = ZEBRA_ROUTE_OSPF;
+ msg.instId = instance;
+ msg.safi = root->safi;
+ msg.add = false;
+ prefix_copy(&msg.root, &root->prefix);
+
+ /* Update prefix table from ORR Route table */
+ for (rn = route_top(root->old_table); rn; rn = route_next(rn)) {
+ or = rn->info;
+ if (!or)
+ continue;
+
+ if (or->path_type != OSPF_PATH_INTRA_AREA &&
+ or->path_type != OSPF_PATH_INTER_AREA)
+ continue;
+
+ if (or->type != OSPF_DESTINATION_NETWORK &&
+ or->type != OSPF_DESTINATION_DISCARD)
+ continue;
+
+ if (ospf_route_exist_new_table(root->new_table,
+ (struct prefix_ipv4 *)&rn->p))
+ continue;
+
+ if (count < ORR_MAX_PREFIX) {
+ prefix_copy(&msg.nexthop[count].prefix,
+ (struct prefix_ipv4 *)&rn->p);
+ msg.nexthop[count].metric = or->cost;
+ count++;
+ } else {
+ msg.num_entries = count;
+ ret = zclient_send_opaque(zclient,
+ ORR_IGP_METRIC_UPDATE,
+ (uint8_t *)&msg, sizeof(msg));
+ if (ret != ZCLIENT_SEND_SUCCESS)
+ ospf_orr_debug(
+ "%s: Failed to send message to BGP.",
+ __func__);
+ count = 0;
+ prefix_copy(&msg.nexthop[count].prefix,
+ (struct prefix_ipv4 *)&rn->p);
+ msg.nexthop[count].metric = or->cost;
+ count++;
+ }
+ }
+ if (count > 0 && count <= ORR_MAX_PREFIX) {
+ msg.num_entries = count;
+ ret = zclient_send_opaque(zclient, ORR_IGP_METRIC_UPDATE,
+ (uint8_t *)&msg, sizeof(msg));
+ if (ret != ZCLIENT_SEND_SUCCESS)
+ ospf_orr_debug("%s: Failed to send message to BGP.",
+ __func__);
+ }
+}
+
+static void ospf_show_orr_root(struct orr_root *root)
+{
+ if (!root)
+ return;
+
+ ospf_orr_debug("%s: Address Family: %s %s", __func__,
+ afi2str(root->afi), safi2str(root->safi));
+ ospf_orr_debug("%s: ORR Group: %s", __func__, root->group_name);
+ ospf_orr_debug("%s: Router-Address: %pI4:", __func__, &root->router_id);
+ ospf_orr_debug("%s: Advertising Router: %pI4:", __func__,
+ &root->adv_router);
+}
+
+static void ospf_show_orr(struct ospf *ospf, afi_t afi, safi_t safi)
+{
+ struct listnode *node = NULL;
+ struct orr_root *orr_root = NULL;
+ struct list *orr_root_list = NULL;
+
+ FOREACH_AFI_SAFI (afi, safi) {
+ orr_root_list = ospf->orr_root[afi][safi];
+ if (!orr_root_list)
+ return;
+
+ for (ALL_LIST_ELEMENTS_RO(orr_root_list, node, orr_root))
+ ospf_show_orr_root(orr_root);
+ }
+}
+
+void ospf_orr_root_table_update(struct ospf_lsa *lsa, bool add)
+{
+ afi_t afi;
+ safi_t safi;
+ struct lsa_header *lsah = lsa->data;
+ uint32_t lsid = ntohl(lsah->id.s_addr);
+ uint8_t opaque_type = GET_OPAQUE_TYPE(lsid);
+ uint32_t opaque_id = GET_OPAQUE_ID(lsid);
+ struct tlv_header *tlvh = TLV_HDR_TOP(lsah);
+ struct te_tlv_router_addr *router_addr = NULL;
+ struct orr_root *root = NULL;
+ struct ospf *ospf = NULL;
+
+ /* if ospf is not enabled ignore */
+ ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
+ if (!ospf)
+ return;
+
+ if (opaque_type != OPAQUE_TYPE_TRAFFIC_ENGINEERING_LSA)
+ return;
+
+ if (!tlvh || (ntohs(tlvh->type) != TE_TLV_ROUTER_ADDR) ||
+ (ntohs(tlvh->length) != TE_LINK_SUBTLV_DEF_SIZE))
+ return;
+
+ router_addr = (struct te_tlv_router_addr *)tlvh;
+ if (IS_DEBUG_OSPF_ORR) {
+ zlog_debug("[OSPF-ORR] %s: Opaque-area LSA %s LSDB", __func__,
+ add ? "added to" : "deleted from");
+ zlog_debug("[OSPF-ORR] %s: Opaque-Type %u (%s)", __func__,
+ opaque_type, "Traffic Engineering LSA");
+ zlog_debug("[OSPF-ORR] %s: Opaque-ID 0x%x", __func__,
+ opaque_id);
+ zlog_debug("[OSPF-ORR] %s: Opaque-Info: %u octets of data%s",
+ __func__, ntohs(lsah->length) - OSPF_LSA_HEADER_SIZE,
+ VALID_OPAQUE_INFO_LEN(lsah) ? ""
+ : "(Invalid length?)");
+ zlog_debug("[OSPF-ORR] %s: Router-Address: %pI4", __func__,
+ &router_addr->value);
+ zlog_debug("[OSPF-ORR] %s: Advertising Router: %pI4", __func__,
+ &lsa->data->adv_router);
+ }
+ /*
+ * When Opaque LSA is added or removed from LSDB check if there is any
+ * change in MPLS-TE Router address and Advertising router address and
+ * update the table accordingly if there is no change in the mapping
+ * ignore update
+ *
+ * Get ORR Root entry for the given address-family
+ */
+ FOREACH_AFI_SAFI (afi, safi) {
+ root = ospf_orr_root_lookup(ospf, afi, safi,
+ &router_addr->value);
+ if (root) {
+ IPV4_ADDR_COPY(&root->adv_router,
+ &lsa->data->adv_router);
+ if (IS_DEBUG_OSPF_ORR)
+ ospf_show_orr(ospf, afi, safi);
+ break;
+ }
+ }
+}
+
+void ospf_orr_root_update_rcvd_lsa(struct ospf_lsa *lsa)
+{
+ afi_t afi;
+ safi_t safi;
+ struct orr_root *root = NULL;
+
+ if (!lsa || !lsa->area || !lsa->area->ospf)
+ return;
+
+ FOREACH_AFI_SAFI (afi, safi) {
+ root = ospf_orr_root_lookup_by_adv_rid(
+ lsa->area->ospf, afi, safi, &lsa->data->adv_router);
+ if (root) {
+ SET_FLAG(lsa->flags, OSPF_LSA_ORR);
+ ospf_refresher_register_lsa(lsa->area->ospf, lsa);
+ root->router_lsa_rcvd = lsa;
+ }
+
+ ospf_orr_debug("%s: Received LSA[Type%d:%pI4]", __func__,
+ lsa->data->type, &lsa->data->adv_router);
+
+ /* Compute SPF for all root nodes */
+ ospf_orr_spf_calculate_schedule(lsa->area->ospf);
+ return;
+ }
+}
+
+/* Do not Install routes to root table. Just update table ponters */
+void ospf_orr_route_install(struct orr_root *root, struct route_table *rt,
+ unsigned short instance)
+{
+ /*
+ * rt contains new routing table, new_table contains an old one.
+ * updating pointers
+ */
+ if (root->old_table)
+ ospf_route_table_free(root->old_table);
+
+ root->old_table = root->new_table;
+ root->new_table = rt;
+
+ /* Send update to BGP to delete old routes. */
+ ospf_orr_igp_metric_send_update_delete(root, instance);
+
+ /* REVISIT: Skipping external route table for now */
+
+ /* Send update to BGP to add new routes. */
+ ospf_orr_igp_metric_send_update_add(root, instance);
+}
+
+void ospf_orr_spf_calculate_schedule(struct ospf *ospf)
+{
+ /* OSPF instance does not exist. */
+ if (ospf == NULL)
+ return;
+
+ /* No roots nodes rgistered for rSPF */
+ if (!ospf->orr_spf_request)
+ return;
+
+ /* ORR SPF calculation timer is already scheduled. */
+ if (ospf->t_orr_calc) {
+ ospf_orr_debug(
+ "SPF: calculation timer is already scheduled: %p",
+ (void *)ospf->t_orr_calc);
+ return;
+ }
+
+ ospf->t_orr_calc = NULL;
+
+ ospf_orr_debug("%s: SPF: calculation timer scheduled", __func__);
+
+ thread_add_timer(master, ospf_orr_spf_calculate_schedule_worker, ospf,
+ OSPF_ORR_CALC_INTERVAL, &ospf->t_orr_calc);
+}
+
+void ospf_orr_spf_calculate_area(struct ospf *ospf, struct ospf_area *area,
+ struct route_table *new_table,
+ struct route_table *all_rtrs,
+ struct route_table *new_rtrs,
+ struct ospf_lsa *lsa_rcvd)
+{
+ ospf_spf_calculate(area, lsa_rcvd, new_table, all_rtrs, new_rtrs, false,
+ true);
+}
+
+void ospf_orr_spf_calculate_areas(struct ospf *ospf,
+ struct route_table *new_table,
+ struct route_table *all_rtrs,
+ struct route_table *new_rtrs,
+ struct ospf_lsa *lsa_rcvd)
+{
+ struct ospf_area *area;
+ struct listnode *node, *nnode;
+
+ /* Calculate SPF for each area. */
+ for (ALL_LIST_ELEMENTS(ospf->areas, node, nnode, area)) {
+ /*
+ * Do backbone last, so as to first discover intra-area paths
+ * for any back-bone virtual-links
+ */
+ if (ospf->backbone && ospf->backbone == area)
+ continue;
+
+ ospf_orr_spf_calculate_area(ospf, area, new_table, all_rtrs,
+ new_rtrs, lsa_rcvd);
+ }
+
+ /* SPF for backbone, if required */
+ if (ospf->backbone)
+ ospf_orr_spf_calculate_area(ospf, ospf->backbone, new_table,
+ all_rtrs, new_rtrs, lsa_rcvd);
+}
diff --git a/ospfd/ospf_orr.h b/ospfd/ospf_orr.h
new file mode 100644
index 000000000..d0a6f6e79
--- /dev/null
+++ b/ospfd/ospf_orr.h
@@ -0,0 +1,58 @@
+/*
+ * OSPF BGP-IGP IGP metric update handling routines
+ * Copyright (C) 2021 Samsung R&D Institute India - Bangalore.
+ * Madhurilatha Kuruganti
+ *
+ * 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 _ZEBRA_OSPF_ORR_H
+#define _ZEBRA_OSPF_ORR_H
+
+#define BGP_OSPF_LSINFINITY 65535
+#define OSPF_ORR_CALC_INTERVAL 1
+
+/* Macro to log debug message */
+#define ospf_orr_debug(...) \
+ do { \
+ if (IS_DEBUG_OSPF_ORR) \
+ zlog_debug("[OSPF-ORR] "__VA_ARGS__); \
+ } while (0)
+
+extern struct zclient *zclient;
+
+extern int ospf_orr_igp_metric_register(struct orr_igp_metric_reg orr_reg);
+extern void ospf_orr_igp_metric_send_update_add(struct orr_root *root,
+ unsigned short instance);
+extern void ospf_orr_igp_metric_send_update_delete(struct orr_root *root,
+ unsigned short instance);
+extern void ospf_orr_root_table_update(struct ospf_lsa *lsa, bool add);
+extern void ospf_orr_root_update_rcvd_lsa(struct ospf_lsa *lsa);
+extern void ospf_orr_route_install(struct orr_root *root,
+ struct route_table *rt,
+ unsigned short instance);
+extern void ospf_orr_spf_calculate_schedule(struct ospf *ospf);
+extern void ospf_orr_spf_calculate_area(struct ospf *ospf,
+ struct ospf_area *area,
+ struct route_table *new_table,
+ struct route_table *all_rtrs,
+ struct route_table *new_rtrs,
+ struct ospf_lsa *lsa_rcvd);
+extern void ospf_orr_spf_calculate_areas(struct ospf *ospf,
+ struct route_table *new_table,
+ struct route_table *all_rtrs,
+ struct route_table *new_rtrs,
+ struct ospf_lsa *lsa_rcvd);
+#endif /* _ZEBRA_OSPF_ORR_H */
diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c
index 57643f637..8c87a568c 100644
--- a/ospfd/ospf_packet.c
+++ b/ospfd/ospf_packet.c
@@ -1716,6 +1716,12 @@ static struct list *ospf_ls_upd_list_lsa(struct ospf_neighbor *nbr,
break;
}
+ if (length < OSPF_LSA_HEADER_SIZE) {
+ flog_warn(EC_OSPF_PACKET,
+ "Link State Update: LSA length too small.");
+ break;
+ }
+
/* Validate the LSA's LS checksum. */
sum = lsah->checksum;
if (!ospf_lsa_checksum_valid(lsah)) {
@@ -4220,7 +4226,8 @@ static void ospf_ls_ack_send_list(struct ospf_interface *oi, struct list *ack,
op->length = length;
/* Decide destination address. */
- if (oi->type == OSPF_IFTYPE_POINTOPOINT)
+ if (oi->type == OSPF_IFTYPE_POINTOPOINT ||
+ oi->type == OSPF_IFTYPE_POINTOMULTIPOINT)
op->dst.s_addr = htonl(OSPF_ALLSPFROUTERS);
else
op->dst.s_addr = dst.s_addr;
diff --git a/ospfd/ospf_route.c b/ospfd/ospf_route.c
index 6360d8ec6..26f593f08 100644
--- a/ospfd/ospf_route.c
+++ b/ospfd/ospf_route.c
@@ -151,8 +151,8 @@ void ospf_route_table_free(struct route_table *rt)
otherwise return 0. Since the ZEBRA-RIB does an implicit
withdraw, it is not necessary to send a delete, an add later
will act like an implicit delete. */
-static int ospf_route_exist_new_table(struct route_table *rt,
- struct prefix_ipv4 *prefix)
+int ospf_route_exist_new_table(struct route_table *rt,
+ struct prefix_ipv4 *prefix)
{
struct route_node *rn;
diff --git a/ospfd/ospf_route.h b/ospfd/ospf_route.h
index fa9478fce..e7e2b651c 100644
--- a/ospfd/ospf_route.h
+++ b/ospfd/ospf_route.h
@@ -172,5 +172,6 @@ extern void ospf_delete_discard_route(struct ospf *, struct route_table *,
struct prefix_ipv4 *);
extern int ospf_route_match_same(struct route_table *, struct prefix_ipv4 *,
struct ospf_route *);
-
+extern int ospf_route_exist_new_table(struct route_table *rt,
+ struct prefix_ipv4 *prefix);
#endif /* _ZEBRA_OSPF_ROUTE_H */
diff --git a/ospfd/ospf_spf.c b/ospfd/ospf_spf.c
index 4edc1de81..24ca4dcbf 100644
--- a/ospfd/ospf_spf.c
+++ b/ospfd/ospf_spf.c
@@ -53,6 +53,8 @@
#include "ospfd/ospf_apiserver.h"
#endif
+#include "ospfd/ospf_orr.h"
+
/* Variables to ensure a SPF scheduled log message is printed only once */
static unsigned int spf_reason_flags = 0;
@@ -1824,6 +1826,36 @@ void ospf_spf_calculate_areas(struct ospf *ospf, struct route_table *new_table,
all_rtrs, new_rtrs);
}
+/* Print Reason for SPF calculation */
+static void ospf_spf_calculation_reason2str(char *rbuf, size_t len)
+{
+ rbuf[0] = '\0';
+ if (spf_reason_flags) {
+ if (spf_reason_flags & (1 << SPF_FLAG_ROUTER_LSA_INSTALL))
+ strlcat(rbuf, "R, ", len);
+ if (spf_reason_flags & (1 << SPF_FLAG_NETWORK_LSA_INSTALL))
+ strlcat(rbuf, "N, ", len);
+ if (spf_reason_flags & (1 << SPF_FLAG_SUMMARY_LSA_INSTALL))
+ strlcat(rbuf, "S, ", len);
+ if (spf_reason_flags & (1 << SPF_FLAG_ASBR_SUMMARY_LSA_INSTALL))
+ strlcat(rbuf, "AS, ", len);
+ if (spf_reason_flags & (1 << SPF_FLAG_ABR_STATUS_CHANGE))
+ strlcat(rbuf, "ABR, ", len);
+ if (spf_reason_flags & (1 << SPF_FLAG_ASBR_STATUS_CHANGE))
+ strlcat(rbuf, "ASBR, ", len);
+ if (spf_reason_flags & (1 << SPF_FLAG_MAXAGE))
+ strlcat(rbuf, "M, ", len);
+ if (spf_reason_flags & (1 << SPF_FLAG_ORR_ROOT_CHANGE))
+ strlcat(rbuf, "ORR, ", len);
+
+ size_t rbuflen = strlen(rbuf);
+ if (rbuflen >= 2)
+ rbuf[rbuflen - 2] = '\0'; /* skip the last ", " */
+ else
+ rbuf[0] = '\0';
+ }
+}
+
/* Worker for SPF calculation scheduler. */
static void ospf_spf_calculate_schedule_worker(struct thread *thread)
{
@@ -1879,6 +1911,8 @@ static void ospf_spf_calculate_schedule_worker(struct thread *thread)
ospf_ase_calculate_schedule(ospf);
ospf_ase_calculate_timer_add(ospf);
+ ospf_orr_spf_calculate_schedule(ospf);
+
if (IS_DEBUG_OSPF_EVENT)
zlog_debug(
"%s: ospf install new route, vrf %s id %u new_table count %lu",
@@ -1901,7 +1935,6 @@ static void ospf_spf_calculate_schedule_worker(struct thread *thread)
#ifdef SUPPORT_OSPF_API
ospf_apiserver_notify_reachable(ospf->oall_rtrs, ospf->all_rtrs);
#endif
-
/* Free old ABR/ASBR routing table */
if (ospf->old_rtrs)
/* ospf_route_delete (ospf->old_rtrs); */
@@ -1926,31 +1959,7 @@ static void ospf_spf_calculate_schedule_worker(struct thread *thread)
total_spf_time =
monotime_since(&spf_start_time, &ospf->ts_spf_duration);
- rbuf[0] = '\0';
- if (spf_reason_flags) {
- if (spf_reason_flags & (1 << SPF_FLAG_ROUTER_LSA_INSTALL))
- strlcat(rbuf, "R, ", sizeof(rbuf));
- if (spf_reason_flags & (1 << SPF_FLAG_NETWORK_LSA_INSTALL))
- strlcat(rbuf, "N, ", sizeof(rbuf));
- if (spf_reason_flags & (1 << SPF_FLAG_SUMMARY_LSA_INSTALL))
- strlcat(rbuf, "S, ", sizeof(rbuf));
- if (spf_reason_flags & (1 << SPF_FLAG_ASBR_SUMMARY_LSA_INSTALL))
- strlcat(rbuf, "AS, ", sizeof(rbuf));
- if (spf_reason_flags & (1 << SPF_FLAG_ABR_STATUS_CHANGE))
- strlcat(rbuf, "ABR, ", sizeof(rbuf));
- if (spf_reason_flags & (1 << SPF_FLAG_ASBR_STATUS_CHANGE))
- strlcat(rbuf, "ASBR, ", sizeof(rbuf));
- if (spf_reason_flags & (1 << SPF_FLAG_MAXAGE))
- strlcat(rbuf, "M, ", sizeof(rbuf));
- if (spf_reason_flags & (1 << SPF_FLAG_GR_FINISH))
- strlcat(rbuf, "GR, ", sizeof(rbuf));
-
- size_t rbuflen = strlen(rbuf);
- if (rbuflen >= 2)
- rbuf[rbuflen - 2] = '\0'; /* skip the last ", " */
- else
- rbuf[0] = '\0';
- }
+ ospf_spf_calculation_reason2str(rbuf, sizeof(rbuf));
if (IS_DEBUG_OSPF_EVENT) {
zlog_info("SPF Processing Time(usecs): %ld", total_spf_time);
@@ -1967,6 +1976,145 @@ static void ospf_spf_calculate_schedule_worker(struct thread *thread)
ospf_clear_spf_reason_flags();
}
+/* Worker for ORR SPF calculation scheduler. */
+void ospf_orr_spf_calculate_schedule_worker(struct thread *thread)
+{
+ afi_t afi;
+ safi_t safi;
+ struct ospf *ospf = THREAD_ARG(thread);
+ struct route_table *new_table, *new_rtrs;
+ struct route_table *all_rtrs = NULL;
+ struct timeval start_time, spf_start_time;
+ unsigned long ia_time, rt_time;
+ unsigned long abr_time, total_spf_time, spf_time;
+ struct listnode *rnode;
+ struct list *orr_root_list;
+ struct orr_root *root;
+ char rbuf[32]; /* reason_buf */
+
+ ospf_orr_debug("%s: SPF: Timer (SPF calculation expire)", __func__);
+
+ ospf->t_orr_calc = NULL;
+
+ /* Execute SPF for each ORR Root node */
+ FOREACH_AFI_SAFI (afi, safi) {
+ orr_root_list = ospf->orr_root[afi][safi];
+ if (!orr_root_list)
+ continue;
+ for (ALL_LIST_ELEMENTS_RO(orr_root_list, rnode, root)) {
+ if (!root || !root->router_lsa_rcvd)
+ continue;
+ ospf_orr_debug(
+ "%s: For %s %s, MPLS TE Router address %pI4 advertised by %pI4",
+ __func__, afi2str(afi), safi2str(safi),
+ &root->router_id, &root->adv_router);
+
+ ospf_vl_unapprove(ospf);
+
+ /*
+ * Execute SPF for each area including backbone, see RFC
+ * 2328 16.1.
+ */
+ monotime(&spf_start_time);
+ new_table = route_table_init(); /* routing table */
+ new_rtrs =
+ route_table_init(); /* ABR/ASBR routing table */
+
+ /*
+ * If we have opaque enabled then track all router
+ * reachability
+ */
+ if (CHECK_FLAG(ospf->opaque,
+ OPAQUE_OPERATION_READY_BIT))
+ all_rtrs = route_table_init();
+ ospf_orr_spf_calculate_areas(ospf, new_table, all_rtrs,
+ new_rtrs,
+ root->router_lsa_rcvd);
+
+ spf_time = monotime_since(&spf_start_time, NULL);
+
+ ospf_vl_shut_unapproved(ospf);
+
+ /* Calculate inter-area routes, see RFC 2328 16.2. */
+ monotime(&start_time);
+ ospf_ia_routing(ospf, new_table, new_rtrs);
+ ia_time = monotime_since(&start_time, NULL);
+
+ /*
+ * REVISIT :
+ * Pruning of unreachable networks, routers skipped.
+ */
+
+ /* Note: RFC 2328 16.3. is apparently missing. */
+ /* Calculate AS external routes, see RFC 2328 16.4.
+ * There is a dedicated routing table for external
+ * routes which is not handled here directly
+ */
+ ospf_ase_calculate_schedule(ospf);
+ ospf_ase_calculate_timer_add(ospf);
+
+ ospf_orr_debug(
+ "%s: ospf install new route, vrf %s id %u new_table count %lu",
+ __func__, ospf_vrf_id_to_name(ospf->vrf_id),
+ ospf->vrf_id, new_table->count);
+
+ /* Update routing table. */
+ monotime(&start_time);
+ ospf_orr_route_install(root, new_table, ospf->instance);
+ rt_time = monotime_since(&start_time, NULL);
+
+ /*
+ * REVISIT :
+ * Freeing up and Updating old all routers routing table
+ * skipped.
+ */
+
+ /* Free old ABR/ASBR routing table */
+ if (root->old_rtrs)
+ /* ospf_route_delete (ospf->old_rtrs); */
+ ospf_rtrs_free(root->old_rtrs);
+
+ /* Update ABR/ASBR routing table */
+ root->old_rtrs = root->new_rtrs;
+ root->new_rtrs = new_rtrs;
+
+ /*
+ * ABRs may require additional changes, see RFC
+ * 2328 16.7.
+ */
+ monotime(&start_time);
+ if (IS_OSPF_ABR(ospf)) {
+ if (ospf->anyNSSA)
+ ospf_abr_nssa_check_status(ospf);
+ ospf_abr_task(ospf);
+ }
+ abr_time = monotime_since(&start_time, NULL);
+
+ /* Schedule Segment Routing update */
+ ospf_sr_update_task(ospf);
+
+ total_spf_time = monotime_since(&spf_start_time,
+ &ospf->ts_spf_duration);
+
+ ospf_spf_calculation_reason2str(rbuf, sizeof(rbuf));
+
+ if (IS_DEBUG_OSPF_ORR) {
+ zlog_info("SPF Processing Time(usecs): %ld",
+ total_spf_time);
+ zlog_info(" SPF Time: %ld",
+ spf_time);
+ zlog_info(" InterArea: %ld", ia_time);
+ zlog_info(" RouteInstall: %ld", rt_time);
+ if (IS_OSPF_ABR(ospf))
+ zlog_info(
+ " ABR: %ld (%d areas)",
+ abr_time, ospf->areas->count);
+ zlog_info("Reason(s) for SPF: %s", rbuf);
+ }
+ } /* ALL_LIST_ELEMENTS_RO() */
+ } /* FOREACH_AFI_SAFI() */
+}
+
/*
* Add schedule for SPF calculation. To avoid frequenst SPF calc, we set timer
* for SPF calc.
@@ -2025,6 +2173,7 @@ void ospf_spf_calculate_schedule(struct ospf *ospf, ospf_spf_reason_t reason)
zlog_debug("SPF: calculation timer delay = %ld msec", delay);
ospf->t_spf_calc = NULL;
+
thread_add_timer_msec(master, ospf_spf_calculate_schedule_worker, ospf,
delay, &ospf->t_spf_calc);
}
diff --git a/ospfd/ospf_spf.h b/ospfd/ospf_spf.h
index 834bfd0bb..2578051c2 100644
--- a/ospfd/ospf_spf.h
+++ b/ospfd/ospf_spf.h
@@ -70,8 +70,10 @@ typedef enum {
SPF_FLAG_ASBR_STATUS_CHANGE,
SPF_FLAG_CONFIG_CHANGE,
SPF_FLAG_GR_FINISH,
+ SPF_FLAG_ORR_ROOT_CHANGE,
} ospf_spf_reason_t;
+extern unsigned int ospf_get_spf_reason_flags(void);
extern void ospf_spf_calculate_schedule(struct ospf *, ospf_spf_reason_t);
extern void ospf_spf_calculate(struct ospf_area *area,
struct ospf_lsa *root_lsa,
@@ -103,5 +105,6 @@ extern int vertex_parent_cmp(void *aa, void *bb);
extern void ospf_spf_print(struct vty *vty, struct vertex *v, int i);
extern void ospf_restart_spf(struct ospf *ospf);
+extern void ospf_orr_spf_calculate_schedule_worker(struct thread *thread);
/* void ospf_spf_calculate_timer_add (); */
#endif /* _QUAGGA_OSPF_SPF_H */
diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
index c957c8c01..0bab045ef 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -55,6 +55,7 @@
#include "ospfd/ospf_dump.h"
#include "ospfd/ospf_bfd.h"
#include "ospfd/ospf_ldp_sync.h"
+#include "ospfd/ospf_orr.h"
FRR_CFG_DEFAULT_BOOL(OSPF_LOG_ADJACENCY_CHANGES,
@@ -184,9 +185,7 @@ static void ospf_show_vrf_name(struct ospf *ospf, struct vty *vty,
}
}
-#ifndef VTYSH_EXTRACT_PL
#include "ospfd/ospf_vty_clippy.c"
-#endif
DEFUN_NOSH (router_ospf,
router_ospf_cmd,
@@ -9412,7 +9411,7 @@ DEFUN (ospf_default_information_originate,
idx = 1;
/* Get route-map */
if (argv_find(argv, argc, "route-map", &idx))
- rtmap = argv[idx]->arg + 1;
+ rtmap = argv[idx + 1]->arg;
/* To check if user is providing same route map */
if ((!rtmap && !ROUTEMAP_NAME(red)) ||
@@ -10531,22 +10530,15 @@ DEFUN (no_ospf_route_aggregation_timer,
static void config_write_stub_router(struct vty *vty, struct ospf *ospf)
{
- struct listnode *ln;
- struct ospf_area *area;
-
if (ospf->stub_router_startup_time != OSPF_STUB_ROUTER_UNCONFIGURED)
vty_out(vty, " max-metric router-lsa on-startup %u\n",
ospf->stub_router_startup_time);
if (ospf->stub_router_shutdown_time != OSPF_STUB_ROUTER_UNCONFIGURED)
vty_out(vty, " max-metric router-lsa on-shutdown %u\n",
ospf->stub_router_shutdown_time);
- for (ALL_LIST_ELEMENTS_RO(ospf->areas, ln, area)) {
- if (CHECK_FLAG(area->stub_router_state,
- OSPF_AREA_ADMIN_STUB_ROUTED)) {
- vty_out(vty, " max-metric router-lsa administrative\n");
- break;
- }
- }
+ if (ospf->stub_router_admin_set == OSPF_STUB_ROUTER_ADMINISTRATIVE_SET)
+ vty_out(vty, " max-metric router-lsa administrative\n");
+
return;
}
@@ -10982,6 +10974,131 @@ static void show_ip_ospf_route_external(struct vty *vty, struct ospf *ospf,
vty_out(vty, "\n");
}
+static void show_ip_ospf_route_orr_root(struct vty *vty, struct ospf *ospf,
+ struct orr_root *root, bool use_vrf)
+{
+ if (ospf->instance)
+ vty_out(vty, "\nOSPF Instance: %d\n", ospf->instance);
+
+ ospf_show_vrf_name(ospf, vty, NULL, use_vrf);
+
+ vty_out(vty, "ORR Group: %s\n", root->group_name);
+ vty_out(vty, "Active Root: %pI4\n\n", &root->router_id);
+ vty_out(vty, "SPF calculated from %pI4\n\n", &root->router_id);
+
+ if (root->new_table)
+ show_ip_ospf_route_network(vty, ospf, root->new_table, NULL);
+
+ if (root->new_rtrs)
+ show_ip_ospf_route_router(vty, ospf, root->new_rtrs, NULL);
+
+ vty_out(vty, "\n");
+}
+
+static void show_ip_ospf_route_orr_common(struct vty *vty, struct ospf *ospf,
+ const char *orr_group, bool use_vrf)
+{
+ afi_t afi;
+ safi_t safi;
+ struct orr_root *root = NULL;
+ struct listnode *node = NULL;
+ struct list *orr_root_list = NULL;
+
+ if (!ospf->orr_spf_request)
+ return;
+
+ FOREACH_AFI_SAFI (afi, safi) {
+ orr_root_list = ospf->orr_root[afi][safi];
+ if (!orr_root_list)
+ continue;
+ for (ALL_LIST_ELEMENTS_RO(orr_root_list, node, root)) {
+ if (orr_group) {
+ if (!strmatch(root->group_name, orr_group))
+ continue;
+ show_ip_ospf_route_orr_root(vty, ospf, root,
+ use_vrf);
+ } else
+ show_ip_ospf_route_orr_root(vty, ospf, root,
+ use_vrf);
+ }
+ }
+}
+
+DEFPY (show_ip_ospf_instance_route_orr,
+ show_ip_ospf_instance_route_orr_cmd,
+ "show ip ospf (1-65535)$instance route orr [WORD$orr_group]",
+ SHOW_STR
+ IP_STR
+ OSPF_STR
+ "Instance ID\n"
+ "OSPF routing table\n"
+ "Optimal Route Reflection\n"
+ "ORR Group name\n")
+{
+ struct ospf *ospf;
+
+ if (instance != ospf_instance)
+ return CMD_NOT_MY_INSTANCE;
+
+ ospf = ospf_lookup_instance(instance);
+ if (!ospf || !ospf->oi_running)
+ return CMD_SUCCESS;
+
+ show_ip_ospf_route_orr_common(vty, ospf, orr_group, false);
+
+ return CMD_SUCCESS;
+}
+
+DEFPY (show_ip_ospf_route_orr,
+ show_ip_ospf_route_orr_cmd,
+ "show ip ospf [vrf <NAME$vrf_name|all$all_vrf>] route orr [WORD$orr_group]",
+ SHOW_STR
+ IP_STR
+ OSPF_STR
+ VRF_CMD_HELP_STR
+ "All VRFs\n"
+ "OSPF routing table\n"
+ "Optimal Route Reflection\n"
+ "ORR Group name\n")
+{
+ struct ospf *ospf = NULL;
+ struct listnode *node = NULL;
+ int ret = CMD_SUCCESS;
+ int inst = 0;
+ bool use_vrf = vrf_name || all_vrf;
+
+ if (all_vrf) {
+ bool ospf_output = false;
+
+ for (ALL_LIST_ELEMENTS_RO(om->ospf, node, ospf)) {
+ if (!ospf->oi_running)
+ continue;
+ ospf_output = true;
+
+ show_ip_ospf_route_orr_common(vty, ospf, orr_group,
+ use_vrf);
+ }
+ if (!ospf_output)
+ vty_out(vty, "%% OSPF is not enabled\n");
+ return ret;
+ }
+
+ if (vrf_name)
+ ospf = ospf_lookup_by_inst_name(inst, vrf_name);
+ else
+ ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT);
+
+ if (!ospf || !ospf->oi_running) {
+ vty_out(vty, "%% OSPF is not enabled in vrf %s\n",
+ vrf_name ? vrf_name : "default");
+ return CMD_SUCCESS;
+ }
+
+ show_ip_ospf_route_orr_common(vty, ospf, orr_group, use_vrf);
+
+ return ret;
+}
+
static int show_ip_ospf_reachable_routers_common(struct vty *vty,
struct ospf *ospf,
uint8_t use_vrf)
@@ -12694,11 +12811,13 @@ void ospf_vty_show_init(void)
install_element(VIEW_NODE, &show_ip_ospf_route_cmd);
install_element(VIEW_NODE, &show_ip_ospf_border_routers_cmd);
install_element(VIEW_NODE, &show_ip_ospf_reachable_routers_cmd);
+ install_element(VIEW_NODE, &show_ip_ospf_route_orr_cmd);
install_element(VIEW_NODE, &show_ip_ospf_instance_route_cmd);
install_element(VIEW_NODE, &show_ip_ospf_instance_border_routers_cmd);
install_element(VIEW_NODE,
&show_ip_ospf_instance_reachable_routers_cmd);
+ install_element(VIEW_NODE, &show_ip_ospf_instance_route_orr_cmd);
/* "show ip ospf vrfs" commands. */
install_element(VIEW_NODE, &show_ip_ospf_vrfs_cmd);
diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c
index 1754512b5..461586424 100644
--- a/ospfd/ospf_zebra.c
+++ b/ospfd/ospf_zebra.c
@@ -53,6 +53,7 @@
#include "ospfd/ospf_te.h"
#include "ospfd/ospf_sr.h"
#include "ospfd/ospf_ldp_sync.h"
+#include "ospfd/ospf_orr.h"
DEFINE_MTYPE_STATIC(OSPFD, OSPF_EXTERNAL, "OSPF External route table");
DEFINE_MTYPE_STATIC(OSPFD, OSPF_REDISTRIBUTE, "OSPF Redistriute");
@@ -2081,6 +2082,7 @@ static void ospf_zebra_connected(struct zclient *zclient)
bfd_client_sendmsg(zclient, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT);
zclient_send_reg_requests(zclient, VRF_DEFAULT);
+ zclient_register_opaque(zclient, ORR_IGP_METRIC_REGISTER);
}
/*
@@ -2093,6 +2095,7 @@ static int ospf_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
struct ldp_igp_sync_if_state state;
struct ldp_igp_sync_announce announce;
struct zapi_opaque_reg_info dst;
+ struct orr_igp_metric_reg orr_reg;
int ret = 0;
s = zclient->ibuf;
@@ -2116,6 +2119,10 @@ static int ospf_opaque_msg_handler(ZAPI_CALLBACK_ARGS)
STREAM_GET(&announce, s, sizeof(announce));
ret = ospf_ldp_sync_announce_update(announce);
break;
+ case ORR_IGP_METRIC_REGISTER:
+ STREAM_GET(&orr_reg, s, sizeof(orr_reg));
+ ret = ospf_orr_igp_metric_register(orr_reg);
+ break;
default:
break;
}
diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c
index e0c36d86f..3f82d8692 100644
--- a/ospfd/ospfd.c
+++ b/ospfd/ospfd.c
@@ -795,6 +795,7 @@ static void ospf_finish_final(struct ospf *ospf)
THREAD_OFF(ospf->t_write);
THREAD_OFF(ospf->t_spf_calc);
THREAD_OFF(ospf->t_ase_calc);
+ THREAD_OFF(ospf->t_orr_calc);
THREAD_OFF(ospf->t_maxage);
THREAD_OFF(ospf->t_maxage_walker);
THREAD_OFF(ospf->t_abr_task);
diff --git a/ospfd/ospfd.h b/ospfd/ospfd.h
index 3a43010f8..c7735136b 100644
--- a/ospfd/ospfd.h
+++ b/ospfd/ospfd.h
@@ -35,6 +35,8 @@
#include "ospf_memory.h"
#include "ospf_dump_api.h"
+#include "orr_msg.h"
+
#define OSPF_VERSION 2
/* VTY port number. */
@@ -261,6 +263,7 @@ struct ospf {
struct thread *t_distribute_update; /* Distirbute list update timer. */
struct thread *t_spf_calc; /* SPF calculation timer. */
struct thread *t_ase_calc; /* ASE calculation timer. */
+ struct thread *t_orr_calc; /* ORR calculation timer. */
struct thread
*t_opaque_lsa_self; /* Type-11 Opaque-LSAs origin event. */
struct thread *t_sr_update; /* Segment Routing update timer */
@@ -406,6 +409,10 @@ struct ospf {
bool ti_lfa_enabled;
enum protection_type ti_lfa_protection_type;
+ /* BGP ORR Root node list */
+ uint32_t orr_spf_request;
+ struct list *orr_root[AFI_MAX][SAFI_MAX];
+
QOBJ_FIELDS;
};
DECLARE_QOBJ_TYPE(ospf);
@@ -591,6 +598,9 @@ struct ospf_area {
uint32_t act_ints; /* Active interfaces. */
uint32_t full_nbrs; /* Fully adjacent neighbors. */
uint32_t full_vls; /* Fully adjacent virtual neighbors. */
+
+ /* BGP-ORR Received LSAs */
+ struct ospf_lsa *router_lsa_rcvd;
};
/* OSPF config network structure. */
diff --git a/ospfd/subdir.am b/ospfd/subdir.am
index 4f9cbc7b1..b67f94288 100644
--- a/ospfd/subdir.am
+++ b/ospfd/subdir.am
@@ -5,18 +5,6 @@
if OSPFD
noinst_LIBRARIES += ospfd/libfrrospf.a
sbin_PROGRAMS += ospfd/ospfd
-vtysh_scan += \
- ospfd/ospf_bfd.c \
- ospfd/ospf_dump.c \
- ospfd/ospf_gr.c \
- ospfd/ospf_ldp_sync.c \
- ospfd/ospf_opaque.c \
- ospfd/ospf_ri.c \
- ospfd/ospf_routemap.c \
- ospfd/ospf_te.c \
- ospfd/ospf_sr.c \
- ospfd/ospf_vty.c \
- # end
vtysh_daemons += ospfd
if SNMP
module_LTLIBRARIES += ospfd/ospfd_snmp.la
@@ -48,6 +36,7 @@ ospfd_libfrrospf_a_SOURCES = \
ospfd/ospf_network.c \
ospfd/ospf_nsm.c \
ospfd/ospf_opaque.c \
+ ospfd/ospf_orr.c \
ospfd/ospf_packet.c \
ospfd/ospf_ri.c \
ospfd/ospf_route.c \
@@ -101,6 +90,7 @@ noinst_HEADERS += \
ospfd/ospf_memory.h \
ospfd/ospf_neighbor.h \
ospfd/ospf_network.h \
+ ospfd/ospf_orr.h \
ospfd/ospf_packet.h \
ospfd/ospf_ri.h \
ospfd/ospf_gr.h \
diff --git a/pathd/path_cli.c b/pathd/path_cli.c
index 4775aa36f..b88453c68 100644
--- a/pathd/path_cli.c
+++ b/pathd/path_cli.c
@@ -31,9 +31,7 @@
#include "pathd/pathd.h"
#include "pathd/path_nb.h"
-#ifndef VTYSH_EXTRACT_PL
#include "pathd/path_cli_clippy.c"
-#endif
#include "pathd/path_ted.h"
#define XPATH_MAXATTRSIZE 64
@@ -128,7 +126,7 @@ DEFPY(show_srte_policy,
ttable_rowseps(tt, 0, BOTTOM, true, '-');
RB_FOREACH (policy, srte_policy_head, &srte_policies) {
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
char binding_sid[16] = "-";
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
@@ -175,7 +173,7 @@ DEFPY(show_srte_policy_detail,
vty_out(vty, "\n");
RB_FOREACH (policy, srte_policy_head, &srte_policies) {
struct srte_candidate *candidate;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
char binding_sid[16] = "-";
char *segment_list_info;
static char undefined_info[] = "(undefined)";
@@ -1092,7 +1090,26 @@ DEFPY_NOSH(show_debugging_pathd, show_debugging_pathd_cmd,
"State of each debugging option\n"
"pathd module debugging\n")
{
+
+ vty_out(vty, "Path debugging status:\n");
+
+ cmd_show_lib_debugs(vty);
/* nothing to do here */
+ path_ted_show_debugging(vty);
+ path_policy_show_debugging(vty);
+ return CMD_SUCCESS;
+}
+
+DEFPY(debug_path_policy, debug_path_policy_cmd, "[no] debug pathd policy",
+ NO_STR DEBUG_STR
+ "path debugging\n"
+ "policy debugging\n")
+{
+ uint32_t mode = DEBUG_NODE2MODE(vty->node);
+ bool no_debug = no;
+
+ DEBUG_MODE_SET(&path_policy_debug, mode, !no);
+ DEBUG_FLAGS_SET(&path_policy_debug, PATH_POLICY_DEBUG_BASIC, !no_debug);
return CMD_SUCCESS;
}
@@ -1291,8 +1308,34 @@ int config_write_segment_routing(struct vty *vty)
return 1;
}
+static int path_policy_cli_debug_config_write(struct vty *vty)
+{
+ if (DEBUG_MODE_CHECK(&path_policy_debug, DEBUG_MODE_CONF)) {
+ if (DEBUG_FLAGS_CHECK(&path_policy_debug,
+ PATH_POLICY_DEBUG_BASIC))
+ vty_out(vty, "debug pathd policy\n");
+ return 1;
+ }
+ return 0;
+}
+
+static int path_policy_cli_debug_set_all(uint32_t flags, bool set)
+{
+ DEBUG_FLAGS_SET(&path_policy_debug, flags, set);
+
+ /* If all modes have been turned off, don't preserve options. */
+ if (!DEBUG_MODE_CHECK(&path_policy_debug, DEBUG_MODE_ALL))
+ DEBUG_CLEAR(&path_policy_debug);
+
+ return 0;
+}
+
void path_cli_init(void)
{
+ hook_register(nb_client_debug_config_write,
+ path_policy_cli_debug_config_write);
+ hook_register(nb_client_debug_set_all, path_policy_cli_debug_set_all);
+
install_node(&segment_routing_node);
install_node(&sr_traffic_eng_node);
install_node(&srte_segment_list_node);
@@ -1308,6 +1351,9 @@ void path_cli_init(void)
install_element(ENABLE_NODE, &show_srte_policy_cmd);
install_element(ENABLE_NODE, &show_srte_policy_detail_cmd);
+ install_element(ENABLE_NODE, &debug_path_policy_cmd);
+ install_element(CONFIG_NODE, &debug_path_policy_cmd);
+
install_element(CONFIG_NODE, &segment_routing_cmd);
install_element(SEGMENT_ROUTING_NODE, &sr_traffic_eng_cmd);
install_element(SR_TRAFFIC_ENG_NODE, &srte_segment_list_cmd);
diff --git a/pathd/path_pcep_cli.c b/pathd/path_pcep_cli.c
index d2b49a7d9..0f259f1dc 100644
--- a/pathd/path_pcep_cli.c
+++ b/pathd/path_pcep_cli.c
@@ -40,9 +40,7 @@
#include "pathd/path_pcep_lib.h"
#include "pathd/path_pcep_pcc.h"
-#ifndef VTYSH_EXTRACT_PL
#include "pathd/path_pcep_cli_clippy.c"
-#endif
#define DEFAULT_PCE_PRECEDENCE 255
#define DEFAULT_PCC_MSD 4
diff --git a/pathd/path_ted.c b/pathd/path_ted.c
index 316255a97..5fc8a1f03 100644
--- a/pathd/path_ted.c
+++ b/pathd/path_ted.c
@@ -29,9 +29,7 @@
#include "pathd/path_errors.h"
#include "pathd/path_ted.h"
-#ifndef VTYSH_EXTRACT_PL
#include "pathd/path_ted_clippy.c"
-#endif
static struct ls_ted *path_ted_create_ted(void);
static void path_ted_register_vty(void);
@@ -162,7 +160,7 @@ bool path_ted_is_initialized(void)
*
* @return Ptr to ted or NULL
*/
-struct ls_ted *path_ted_create_ted()
+struct ls_ted *path_ted_create_ted(void)
{
struct ls_ted *ted = ls_ted_new(TED_KEY, TED_NAME, TED_ASN);
@@ -490,6 +488,12 @@ int path_ted_cli_debug_config_write(struct vty *vty)
return 0;
}
+void path_ted_show_debugging(struct vty *vty)
+{
+ if (DEBUG_FLAGS_CHECK(&ted_state_g.dbg, PATH_TED_DEBUG_BASIC))
+ vty_out(vty, " Path TED debugging is on\n");
+}
+
int path_ted_cli_debug_set_all(uint32_t flags, bool set)
{
DEBUG_FLAGS_SET(&ted_state_g.dbg, flags, set);
diff --git a/pathd/path_ted.h b/pathd/path_ted.h
index c6897b152..5a0c8eecd 100644
--- a/pathd/path_ted.h
+++ b/pathd/path_ted.h
@@ -101,6 +101,7 @@ int path_ted_segment_list_refresh(void);
/* TED configuration functions */
uint32_t path_ted_config_write(struct vty *vty);
+void path_ted_show_debugging(struct vty *vty);
/* TED util functions */
/* clang-format off */
diff --git a/pathd/pathd.c b/pathd/pathd.c
index e9d7cc6fc..167c88aea 100644
--- a/pathd/pathd.c
+++ b/pathd/pathd.c
@@ -23,6 +23,8 @@
#include "lib_errors.h"
#include "network.h"
#include "libfrr.h"
+#include <debug.h>
+#include <hook.h>
#include "pathd/pathd.h"
#include "pathd/path_zebra.h"
@@ -44,6 +46,17 @@ DEFINE_HOOK(pathd_candidate_updated, (struct srte_candidate * candidate),
DEFINE_HOOK(pathd_candidate_removed, (struct srte_candidate * candidate),
(candidate));
+struct debug path_policy_debug;
+
+#define PATH_POLICY_DEBUG(fmt, ...) \
+ do { \
+ if (DEBUG_FLAGS_CHECK(&path_policy_debug, \
+ PATH_POLICY_DEBUG_BASIC)) \
+ DEBUGD(&path_policy_debug, "policy: " fmt, \
+ ##__VA_ARGS__); \
+ } while (0)
+
+
static void trigger_pathd_candidate_created(struct srte_candidate *candidate);
static void trigger_pathd_candidate_created_timer(struct thread *thread);
static void trigger_pathd_candidate_updated(struct srte_candidate *candidate);
@@ -97,6 +110,20 @@ RB_GENERATE(srte_policy_head, srte_policy, entry, srte_policy_compare)
struct srte_policy_head srte_policies = RB_INITIALIZER(&srte_policies);
+static void srte_policy_status_log(struct srte_policy *policy)
+{
+ char endpoint[ENDPOINT_STR_LENGTH];
+
+ ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
+ if (policy->status == SRTE_POLICY_STATUS_DOWN) {
+ PATH_POLICY_DEBUG("SR-TE(%s, %u): policy is DOWN", endpoint,
+ policy->color);
+ } else if (policy->status == SRTE_POLICY_STATUS_UP) {
+ PATH_POLICY_DEBUG("SR-TE(%s, %u): policy is UP", endpoint,
+ policy->color);
+ }
+}
+
/**
* Adds a segment list to pathd.
*
@@ -531,6 +558,10 @@ void srte_apply_changes(void)
RB_FOREACH_SAFE (policy, srte_policy_head, &srte_policies, safe_pol) {
if (CHECK_FLAG(policy->flags, F_POLICY_DELETED)) {
+ if (policy->status != SRTE_POLICY_STATUS_DOWN) {
+ policy->status = SRTE_POLICY_STATUS_DOWN;
+ srte_policy_status_log(policy);
+ }
srte_policy_del(policy);
continue;
}
@@ -565,7 +596,7 @@ void srte_policy_apply_changes(struct srte_policy *policy)
struct srte_candidate *candidate, *safe;
struct srte_candidate *old_best_candidate;
struct srte_candidate *new_best_candidate;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
@@ -574,8 +605,7 @@ void srte_policy_apply_changes(struct srte_policy *policy)
new_best_candidate = srte_policy_best_candidate(policy);
if (new_best_candidate != old_best_candidate) {
- /* TODO: add debug guard. */
- zlog_debug(
+ PATH_POLICY_DEBUG(
"SR-TE(%s, %u): best candidate changed from %s to %s",
endpoint, policy->color,
old_best_candidate ? old_best_candidate->name : "none",
@@ -617,10 +647,10 @@ void srte_policy_apply_changes(struct srte_policy *policy)
F_SEGMENT_LIST_MODIFIED);
if (candidate_changed || segment_list_changed) {
- /* TODO: add debug guard. */
- zlog_debug("SR-TE(%s, %u): best candidate %s changed",
- endpoint, policy->color,
- new_best_candidate->name);
+ PATH_POLICY_DEBUG(
+ "SR-TE(%s, %u): best candidate %s changed",
+ endpoint, policy->color,
+ new_best_candidate->name);
path_zebra_add_sr_policy(
policy, new_best_candidate->lsp->segment_list);
@@ -722,10 +752,10 @@ void srte_candidate_set_bandwidth(struct srte_candidate *candidate,
float bandwidth, bool required)
{
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
- zlog_debug(
+ PATH_POLICY_DEBUG(
"SR-TE(%s, %u): candidate %s %sconfig bandwidth set to %f B/s",
endpoint, policy->color, candidate->name,
required ? "required " : "", bandwidth);
@@ -750,11 +780,13 @@ void srte_lsp_set_bandwidth(struct srte_lsp *lsp, float bandwidth,
{
struct srte_candidate *candidate = lsp->candidate;
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
+
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
- zlog_debug("SR-TE(%s, %u): candidate %s %slsp bandwidth set to %f B/s",
- endpoint, policy->color, candidate->name,
- required ? "required" : "", bandwidth);
+ PATH_POLICY_DEBUG(
+ "SR-TE(%s, %u): candidate %s %slsp bandwidth set to %f B/s",
+ endpoint, policy->color, candidate->name,
+ required ? "required" : "", bandwidth);
SET_FLAG(lsp->flags, F_CANDIDATE_HAS_BANDWIDTH);
COND_FLAG(lsp->flags, F_CANDIDATE_REQUIRED_BANDWIDTH, required);
lsp->bandwidth = bandwidth;
@@ -770,10 +802,11 @@ void srte_lsp_set_bandwidth(struct srte_lsp *lsp, float bandwidth,
void srte_candidate_unset_bandwidth(struct srte_candidate *candidate)
{
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
+
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
- zlog_debug("SR-TE(%s, %u): candidate %s config bandwidth unset",
- endpoint, policy->color, candidate->name);
+ PATH_POLICY_DEBUG("SR-TE(%s, %u): candidate %s config bandwidth unset",
+ endpoint, policy->color, candidate->name);
UNSET_FLAG(candidate->flags, F_CANDIDATE_HAS_BANDWIDTH);
UNSET_FLAG(candidate->flags, F_CANDIDATE_REQUIRED_BANDWIDTH);
candidate->bandwidth = 0;
@@ -792,10 +825,11 @@ void srte_lsp_unset_bandwidth(struct srte_lsp *lsp)
{
struct srte_candidate *candidate = lsp->candidate;
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
+
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
- zlog_debug("SR-TE(%s, %u): candidate %s lsp bandwidth unset", endpoint,
- policy->color, candidate->name);
+ PATH_POLICY_DEBUG("SR-TE(%s, %u): candidate %s lsp bandwidth unset",
+ endpoint, policy->color, candidate->name);
UNSET_FLAG(lsp->flags, F_CANDIDATE_HAS_BANDWIDTH);
UNSET_FLAG(lsp->flags, F_CANDIDATE_REQUIRED_BANDWIDTH);
SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
@@ -820,9 +854,10 @@ void srte_candidate_set_metric(struct srte_candidate *candidate,
bool is_computed)
{
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
+
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
- zlog_debug(
+ PATH_POLICY_DEBUG(
"SR-TE(%s, %u): candidate %s %sconfig metric %s (%u) set to %f (is-bound: %s; is_computed: %s)",
endpoint, policy->color, candidate->name,
required ? "required " : "", srte_candidate_metric_name(type),
@@ -854,9 +889,10 @@ void srte_lsp_set_metric(struct srte_lsp *lsp,
{
struct srte_candidate *candidate = lsp->candidate;
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
+
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
- zlog_debug(
+ PATH_POLICY_DEBUG(
"SR-TE(%s, %u): candidate %s %slsp metric %s (%u) set to %f (is-bound: %s; is_computed: %s)",
endpoint, policy->color, candidate->name,
required ? "required " : "", srte_candidate_metric_name(type),
@@ -889,11 +925,13 @@ void srte_candidate_unset_metric(struct srte_candidate *candidate,
enum srte_candidate_metric_type type)
{
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
+
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
- zlog_debug("SR-TE(%s, %u): candidate %s config metric %s (%u) unset",
- endpoint, policy->color, candidate->name,
- srte_candidate_metric_name(type), type);
+ PATH_POLICY_DEBUG(
+ "SR-TE(%s, %u): candidate %s config metric %s (%u) unset",
+ endpoint, policy->color, candidate->name,
+ srte_candidate_metric_name(type), type);
assert((type > 0) && (type <= MAX_METRIC_TYPE));
srte_unset_metric(&candidate->metrics[type - 1]);
srte_lsp_unset_metric(candidate->lsp, type);
@@ -913,11 +951,13 @@ void srte_lsp_unset_metric(struct srte_lsp *lsp,
{
struct srte_candidate *candidate = lsp->candidate;
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
+
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
- zlog_debug("SR-TE(%s, %u): candidate %s lsp metric %s (%u) unset",
- endpoint, policy->color, candidate->name,
- srte_candidate_metric_name(type), type);
+ PATH_POLICY_DEBUG(
+ "SR-TE(%s, %u): candidate %s lsp metric %s (%u) unset",
+ endpoint, policy->color, candidate->name,
+ srte_candidate_metric_name(type), type);
assert((type > 0) && (type <= MAX_METRIC_TYPE));
srte_unset_metric(&lsp->metrics[type - 1]);
}
@@ -941,16 +981,18 @@ void srte_candidate_set_objfun(struct srte_candidate *candidate, bool required,
enum objfun_type type)
{
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
+
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
candidate->objfun = type;
SET_FLAG(candidate->flags, F_CANDIDATE_HAS_OBJFUN);
COND_FLAG(candidate->flags, F_CANDIDATE_REQUIRED_OBJFUN, required);
SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
- zlog_debug("SR-TE(%s, %u): candidate %s %sobjective function set to %s",
- endpoint, policy->color, candidate->name,
- required ? "required " : "", objfun_type_name(type));
+ PATH_POLICY_DEBUG(
+ "SR-TE(%s, %u): candidate %s %sobjective function set to %s",
+ endpoint, policy->color, candidate->name,
+ required ? "required " : "", objfun_type_name(type));
}
/**
@@ -961,14 +1003,15 @@ void srte_candidate_set_objfun(struct srte_candidate *candidate, bool required,
void srte_candidate_unset_objfun(struct srte_candidate *candidate)
{
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
+
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
UNSET_FLAG(candidate->flags, F_CANDIDATE_HAS_OBJFUN);
UNSET_FLAG(candidate->flags, F_CANDIDATE_REQUIRED_OBJFUN);
SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
candidate->objfun = OBJFUN_UNDEFINED;
- zlog_debug(
+ PATH_POLICY_DEBUG(
"SR-TE(%s, %u): candidate %s objective functions preferences unset",
endpoint, policy->color, candidate->name);
}
@@ -1013,7 +1056,8 @@ void srte_candidate_set_affinity_filter(struct srte_candidate *candidate,
uint32_t filter)
{
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
+
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
assert(type > AFFINITY_FILTER_UNDEFINED);
@@ -1021,7 +1065,7 @@ void srte_candidate_set_affinity_filter(struct srte_candidate *candidate,
SET_FLAG(candidate->flags, filter_type_to_flag(type));
SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
candidate->affinity_filters[type - 1] = filter;
- zlog_debug(
+ PATH_POLICY_DEBUG(
"SR-TE(%s, %u): candidate %s affinity filter %s set to 0x%08x",
endpoint, policy->color, candidate->name,
filter_type_name(type), filter);
@@ -1038,7 +1082,8 @@ void srte_candidate_unset_affinity_filter(struct srte_candidate *candidate,
enum affinity_filter_type type)
{
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
+
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
assert(type > AFFINITY_FILTER_UNDEFINED);
@@ -1046,9 +1091,10 @@ void srte_candidate_unset_affinity_filter(struct srte_candidate *candidate,
UNSET_FLAG(candidate->flags, filter_type_to_flag(type));
SET_FLAG(candidate->flags, F_CANDIDATE_MODIFIED);
candidate->affinity_filters[type - 1] = 0;
- zlog_debug("SR-TE(%s, %u): candidate %s affinity filter %s unset",
- endpoint, policy->color, candidate->name,
- filter_type_name(type));
+ PATH_POLICY_DEBUG(
+ "SR-TE(%s, %u): candidate %s affinity filter %s unset",
+ endpoint, policy->color, candidate->name,
+ filter_type_name(type));
}
/**
@@ -1093,10 +1139,11 @@ srte_segment_entry_find(struct srte_segment_list *segment_list, uint32_t index)
void srte_candidate_status_update(struct srte_candidate *candidate, int status)
{
struct srte_policy *policy = candidate->policy;
- char endpoint[46];
+ char endpoint[ENDPOINT_STR_LENGTH];
+
ipaddr2str(&policy->endpoint, endpoint, sizeof(endpoint));
- zlog_debug("SR-TE(%s, %u): zebra updated status to %d", endpoint,
- policy->color, status);
+ PATH_POLICY_DEBUG("SR-TE(%s, %u): zebra updated status to %d", endpoint,
+ policy->color, status);
switch (status) {
case ZEBRA_SR_POLICY_DOWN:
switch (policy->status) {
@@ -1109,9 +1156,8 @@ void srte_candidate_status_update(struct srte_candidate *candidate, int status)
case SRTE_POLICY_STATUS_DOWN:
return;
default:
- zlog_debug("SR-TE(%s, %u): policy is DOWN", endpoint,
- policy->color);
policy->status = SRTE_POLICY_STATUS_DOWN;
+ srte_policy_status_log(policy);
break;
}
break;
@@ -1120,9 +1166,8 @@ void srte_candidate_status_update(struct srte_candidate *candidate, int status)
case SRTE_POLICY_STATUS_UP:
return;
default:
- zlog_debug("SR-TE(%s, %u): policy is UP", endpoint,
- policy->color);
policy->status = SRTE_POLICY_STATUS_UP;
+ srte_policy_status_log(policy);
break;
}
break;
@@ -1148,19 +1193,20 @@ void srte_candidate_unset_segment_list(const char *originator, bool force)
return;
}
- zlog_debug("Unset segment lists for originator %s", originator);
+ PATH_POLICY_DEBUG("Unset segment lists for originator %s", originator);
/* Iterate the policies, then iterate each policy's candidate path
* to check the candidate path's segment list originator */
struct srte_policy *policy;
RB_FOREACH (policy, srte_policy_head, &srte_policies) {
- zlog_debug("Unset segment lists checking policy %s",
- policy->name);
+ PATH_POLICY_DEBUG("Unset segment lists checking policy %s",
+ policy->name);
struct srte_candidate *candidate;
RB_FOREACH (candidate, srte_candidate_head,
&policy->candidate_paths) {
- zlog_debug("Unset segment lists checking candidate %s",
- candidate->name);
+ PATH_POLICY_DEBUG(
+ "Unset segment lists checking candidate %s",
+ candidate->name);
if (candidate->lsp == NULL) {
continue;
}
@@ -1190,8 +1236,8 @@ void srte_candidate_unset_segment_list(const char *originator, bool force)
sizeof(segment_list->originator))
== 0
|| force) {
- zlog_debug("Unset segment list %s",
- segment_list->name);
+ PATH_POLICY_DEBUG("Unset segment list %s",
+ segment_list->name);
SET_FLAG(segment_list->flags,
F_SEGMENT_LIST_DELETED);
SET_FLAG(candidate->flags,
@@ -1222,6 +1268,12 @@ const char *srte_origin2str(enum srte_protocol_origin origin)
}
}
+void path_policy_show_debugging(struct vty *vty)
+{
+ if (DEBUG_FLAGS_CHECK(&path_policy_debug, PATH_POLICY_DEBUG_BASIC))
+ vty_out(vty, " Path policy debugging is on\n");
+}
+
void pathd_shutdown(void)
{
path_ted_teardown();
@@ -1347,8 +1399,9 @@ int32_t srte_ted_do_query_type_c(struct srte_segment_entry *entry,
zlog_warn(" %s: PATHD-TED: SL: ERROR query C : ted-sid (%d)",
__func__, ted_sid);
} else {
- zlog_debug("%s: PATHD-TED: SL: Success query C : ted-sid (%d)",
- __func__, ted_sid);
+ PATH_TED_DEBUG(
+ "%s: PATHD-TED: SL: Success query C : ted-sid (%d)",
+ __func__, ted_sid);
}
if (CHECK_SID(entry->segment_list->protocol_origin, ted_sid,
entry->sid_value)) {
@@ -1377,8 +1430,9 @@ int32_t srte_ted_do_query_type_e(struct srte_segment_entry *entry,
zlog_warn(" %s: PATHD-TED: SL: ERROR query E : ted-sid (%d)",
__func__, ted_sid);
} else {
- zlog_debug("%s: PATHD-TED: SL: Success query E : ted-sid (%d)",
- __func__, ted_sid);
+ PATH_TED_DEBUG(
+ "%s: PATHD-TED: SL: Success query E : ted-sid (%d)",
+ __func__, ted_sid);
}
if (CHECK_SID(entry->segment_list->protocol_origin, ted_sid,
entry->sid_value)) {
@@ -1406,8 +1460,8 @@ int32_t srte_ted_do_query_type_f(struct srte_segment_entry *entry,
zlog_warn("%s:SL: ERROR query F : ted-sid (%d)", __func__,
ted_sid);
} else {
- zlog_debug("%s:SL: Success query F : ted-sid (%d)", __func__,
- ted_sid);
+ PATH_TED_DEBUG("%s:SL: Success query F : ted-sid (%d)",
+ __func__, ted_sid);
}
if (CHECK_SID(entry->segment_list->protocol_origin, ted_sid,
entry->sid_value)) {
diff --git a/pathd/pathd.h b/pathd/pathd.h
index 81d7aa910..bb2e63c04 100644
--- a/pathd/pathd.h
+++ b/pathd/pathd.h
@@ -43,6 +43,10 @@ enum srte_protocol_origin {
SRTE_ORIGIN_LOCAL = 3,
};
+extern struct debug path_policy_debug;
+
+#define PATH_POLICY_DEBUG_BASIC 0x01
+
enum srte_policy_status {
SRTE_POLICY_STATUS_UNKNOWN = 0,
SRTE_POLICY_STATUS_DOWN = 1,
@@ -326,6 +330,8 @@ struct srte_candidate {
RB_HEAD(srte_candidate_head, srte_candidate);
RB_PROTOTYPE(srte_candidate_head, srte_candidate, entry, srte_candidate_compare)
+#define ENDPOINT_STR_LENGTH IPADDR_STRING_SIZE
+
struct srte_policy {
RB_ENTRY(srte_policy) entry;
@@ -444,6 +450,7 @@ void srte_candidate_status_update(struct srte_candidate *candidate, int status);
void srte_candidate_unset_segment_list(const char *originator, bool force);
const char *srte_origin2str(enum srte_protocol_origin origin);
void pathd_shutdown(void);
+void path_policy_show_debugging(struct vty *vty);
/* path_cli.c */
void path_cli_init(void);
diff --git a/pathd/subdir.am b/pathd/subdir.am
index f339c7922..29be8f463 100644
--- a/pathd/subdir.am
+++ b/pathd/subdir.am
@@ -5,16 +5,11 @@
if PATHD
noinst_LIBRARIES += pathd/libpath.a
sbin_PROGRAMS += pathd/pathd
-vtysh_scan += \
- pathd/path_cli.c \
- pathd/path_ted.c \
- #end
vtysh_daemons += pathd
# TODO add man page
#man8 += $(MANBUILD)/pathd.8
if PATHD_PCEP
-vtysh_scan += pathd/path_pcep_cli.c
module_LTLIBRARIES += pathd/pathd_pcep.la
endif
diff --git a/pbrd/pbr_debug.c b/pbrd/pbr_debug.c
index 82f045c46..99489777e 100644
--- a/pbrd/pbr_debug.c
+++ b/pbrd/pbr_debug.c
@@ -23,9 +23,7 @@
#include "command.h"
#include "vector.h"
-#ifndef VTYSH_EXTRACT_PL
#include "pbrd/pbr_debug_clippy.c"
-#endif
#include "pbrd/pbr_debug.h"
struct debug pbr_dbg_map = {0, "PBR map"};
diff --git a/pbrd/pbr_main.c b/pbrd/pbr_main.c
index 59aa3676b..28a7b62d1 100644
--- a/pbrd/pbr_main.c
+++ b/pbrd/pbr_main.c
@@ -160,10 +160,9 @@ int main(int argc, char **argv, char **envp)
pbr_debug_init();
- nexthop_group_init(pbr_nhgroup_add_cb,
+ nexthop_group_init(pbr_nhgroup_add_cb, pbr_nhgroup_modify_cb,
pbr_nhgroup_add_nexthop_cb,
- pbr_nhgroup_del_nexthop_cb,
- pbr_nhgroup_delete_cb);
+ pbr_nhgroup_del_nexthop_cb, pbr_nhgroup_delete_cb);
/*
* So we safely ignore these commands since
diff --git a/pbrd/pbr_nht.c b/pbrd/pbr_nht.c
index cbff4832a..298c96151 100644
--- a/pbrd/pbr_nht.c
+++ b/pbrd/pbr_nht.c
@@ -229,6 +229,10 @@ void pbr_nhgroup_add_cb(const char *name)
pbr_map_check_nh_group_change(name);
}
+void pbr_nhgroup_modify_cb(const struct nexthop_group_cmd *nhgc)
+{
+}
+
void pbr_nhgroup_add_nexthop_cb(const struct nexthop_group_cmd *nhgc,
const struct nexthop *nhop)
{
diff --git a/pbrd/pbr_nht.h b/pbrd/pbr_nht.h
index ecc92cc05..900b7627f 100644
--- a/pbrd/pbr_nht.h
+++ b/pbrd/pbr_nht.h
@@ -96,6 +96,7 @@ extern void pbr_nht_set_rule_range(uint32_t low, uint32_t high);
extern uint32_t pbr_nht_get_next_rule(uint32_t seqno);
extern void pbr_nhgroup_add_cb(const char *name);
+extern void pbr_nhgroup_modify_cb(const struct nexthop_group_cmd *nhgc);
extern void pbr_nhgroup_add_nexthop_cb(const struct nexthop_group_cmd *nhg,
const struct nexthop *nhop);
extern void pbr_nhgroup_del_nexthop_cb(const struct nexthop_group_cmd *nhg,
diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c
index a2b3431b9..e8e5981ec 100644
--- a/pbrd/pbr_vty.c
+++ b/pbrd/pbr_vty.c
@@ -36,9 +36,7 @@
#include "pbrd/pbr_zebra.h"
#include "pbrd/pbr_vty.h"
#include "pbrd/pbr_debug.h"
-#ifndef VTYSH_EXTRACT_PL
#include "pbrd/pbr_vty_clippy.c"
-#endif
DEFUN_NOSH(pbr_map, pbr_map_cmd, "pbr-map PBRMAP seq (1-700)",
"Create pbr-map or enter pbr-map command mode\n"
@@ -1243,6 +1241,8 @@ DEFUN_NOSH(show_debugging_pbr,
pbr_debug_config_write_helper(vty, false);
+ cmd_show_lib_debugs(vty);
+
return CMD_SUCCESS;
}
diff --git a/pbrd/subdir.am b/pbrd/subdir.am
index bbe3f2ab7..8a3bf31bf 100644
--- a/pbrd/subdir.am
+++ b/pbrd/subdir.am
@@ -5,10 +5,6 @@
if PBRD
noinst_LIBRARIES += pbrd/libpbr.a
sbin_PROGRAMS += pbrd/pbrd
-vtysh_scan += \
- pbrd/pbr_vty.c \
- pbrd/pbr_debug.c \
- # end
vtysh_daemons += pbrd
man8 += $(MANBUILD)/frr-pbrd.8
endif
diff --git a/pceplib/pcep_msg_messages.c b/pceplib/pcep_msg_messages.c
index 9bbfc5372..5a244098d 100644
--- a/pceplib/pcep_msg_messages.c
+++ b/pceplib/pcep_msg_messages.c
@@ -163,7 +163,7 @@ pcep_msg_create_error_with_objects(uint8_t error_type, uint8_t error_value,
return message;
}
-struct pcep_message *pcep_msg_create_keepalive()
+struct pcep_message *pcep_msg_create_keepalive(void)
{
return (pcep_msg_create_common(PCEP_TYPE_KEEPALIVE));
}
diff --git a/pceplib/pcep_msg_messages_encoding.c b/pceplib/pcep_msg_messages_encoding.c
index e90ca1cfd..2d27e4040 100644
--- a/pceplib/pcep_msg_messages_encoding.c
+++ b/pceplib/pcep_msg_messages_encoding.c
@@ -348,7 +348,7 @@ struct pcep_message *pcep_decode_message(const uint8_t *msg_buf)
return msg;
}
-struct pcep_versioning *create_default_pcep_versioning()
+struct pcep_versioning *create_default_pcep_versioning(void)
{
struct pcep_versioning *versioning =
pceplib_malloc(PCEPLIB_INFRA, sizeof(struct pcep_versioning));
diff --git a/pceplib/pcep_pcc.c b/pceplib/pcep_pcc.c
index 18ccf250a..47e357729 100644
--- a/pceplib/pcep_pcc.c
+++ b/pceplib/pcep_pcc.c
@@ -74,7 +74,6 @@ static const short DEFAULT_SRC_TCP_PORT = 4999;
// Private fn's
struct cmd_line_args *get_cmdline_args(int argc, char *argv[]);
void handle_signal_action(int sig_number);
-int setup_signals(void);
void send_pce_path_request_message(pcep_session *session);
void send_pce_report_message(pcep_session *session);
void print_queue_event(struct pcep_event *event);
@@ -211,8 +210,7 @@ void handle_signal_action(int sig_number)
}
}
-
-int setup_signals()
+static int setup_signals(void)
{
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
diff --git a/pceplib/pcep_pcc_api.c b/pceplib/pcep_pcc_api.c
index b7813c5a0..75c2b59b6 100644
--- a/pceplib/pcep_pcc_api.c
+++ b/pceplib/pcep_pcc_api.c
@@ -55,7 +55,7 @@ const char UNKNOWN_EVENT_STR[] = "UNKNOWN Event Type";
/* Session Logic Handle managed in pcep_session_logic.c */
extern pcep_event_queue *session_logic_event_queue_;
-bool initialize_pcc()
+bool initialize_pcc(void)
{
if (!run_session_logic()) {
pcep_log(LOG_ERR, "%s: Error initializing PCC session logic.",
@@ -85,13 +85,13 @@ bool initialize_pcc_infra(struct pceplib_infra_config *infra_config)
/* this function is blocking */
-bool initialize_pcc_wait_for_completion()
+bool initialize_pcc_wait_for_completion(void)
{
return run_session_logic_wait_for_completion();
}
-bool destroy_pcc()
+bool destroy_pcc(void)
{
if (!stop_session_logic()) {
pcep_log(LOG_WARNING, "%s: Error stopping PCC session logic.",
@@ -103,7 +103,7 @@ bool destroy_pcc()
}
-pcep_configuration *create_default_pcep_configuration()
+pcep_configuration *create_default_pcep_configuration(void)
{
pcep_configuration *config =
pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_configuration));
@@ -226,7 +226,7 @@ void send_message(pcep_session *session, struct pcep_message *msg,
}
/* Returns true if the queue is empty, false otherwise */
-bool event_queue_is_empty()
+bool event_queue_is_empty(void)
{
if (session_logic_event_queue_ == NULL) {
pcep_log(
@@ -246,7 +246,7 @@ bool event_queue_is_empty()
/* Return the number of events on the queue, 0 if empty */
-uint32_t event_queue_num_events_available()
+uint32_t event_queue_num_events_available(void)
{
if (session_logic_event_queue_ == NULL) {
pcep_log(
@@ -266,7 +266,7 @@ uint32_t event_queue_num_events_available()
/* Return the next event on the queue, NULL if empty */
-struct pcep_event *event_queue_get_event()
+struct pcep_event *event_queue_get_event(void)
{
if (session_logic_event_queue_ == NULL) {
pcep_log(
diff --git a/pceplib/pcep_session_logic.c b/pceplib/pcep_session_logic.c
index 78d107255..02cf3bffb 100644
--- a/pceplib/pcep_session_logic.c
+++ b/pceplib/pcep_session_logic.c
@@ -111,7 +111,7 @@ static bool run_session_logic_common(void)
}
-bool run_session_logic()
+bool run_session_logic(void)
{
if (!run_session_logic_common()) {
return false;
@@ -234,7 +234,7 @@ bool run_session_logic_with_infra(pceplib_infra_config *infra_config)
return true;
}
-bool run_session_logic_wait_for_completion()
+bool run_session_logic_wait_for_completion(void)
{
if (!run_session_logic()) {
return false;
@@ -247,7 +247,7 @@ bool run_session_logic_wait_for_completion()
}
-bool stop_session_logic()
+bool stop_session_logic(void)
{
if (session_logic_handle_ == NULL) {
pcep_log(LOG_WARNING, "%s: Session logic already stopped",
diff --git a/pceplib/pcep_socket_comm.c b/pceplib/pcep_socket_comm.c
index e22eb6e67..4a97c8489 100644
--- a/pceplib/pcep_socket_comm.c
+++ b/pceplib/pcep_socket_comm.c
@@ -62,7 +62,7 @@ int socket_fd_node_compare(void *list_entry, void *new_entry)
}
-bool initialize_socket_comm_pre()
+bool initialize_socket_comm_pre(void)
{
socket_comm_handle_ =
pceplib_malloc(PCEPLIB_INFRA, sizeof(pcep_socket_comm_handle));
@@ -129,7 +129,7 @@ bool initialize_socket_comm_external_infra(
return true;
}
-bool initialize_socket_comm_loop()
+bool initialize_socket_comm_loop(void)
{
if (socket_comm_handle_ != NULL) {
/* already initialized */
@@ -152,7 +152,7 @@ bool initialize_socket_comm_loop()
}
-bool destroy_socket_comm_loop()
+bool destroy_socket_comm_loop(void)
{
socket_comm_handle_->active = false;
diff --git a/pceplib/pcep_timers.c b/pceplib/pcep_timers.c
index b0f3e70b5..61fda1636 100644
--- a/pceplib/pcep_timers.c
+++ b/pceplib/pcep_timers.c
@@ -197,7 +197,7 @@ void free_all_timers(pcep_timers_context *timers_context)
}
-bool teardown_timers()
+bool teardown_timers(void)
{
if (timers_context_ == NULL) {
pcep_log(
@@ -252,7 +252,7 @@ bool teardown_timers()
}
-int get_next_timer_id()
+int get_next_timer_id(void)
{
if (timer_id_ == INT_MAX) {
timer_id_ = 0;
diff --git a/pceplib/pcep_utils_double_linked_list.c b/pceplib/pcep_utils_double_linked_list.c
index 696e46632..7f90df40f 100644
--- a/pceplib/pcep_utils_double_linked_list.c
+++ b/pceplib/pcep_utils_double_linked_list.c
@@ -31,7 +31,7 @@
#include "pcep_utils_logging.h"
#include "pcep_utils_memory.h"
-double_linked_list *dll_initialize()
+double_linked_list *dll_initialize(void)
{
double_linked_list *handle =
pceplib_malloc(PCEPLIB_INFRA, sizeof(double_linked_list));
diff --git a/pceplib/pcep_utils_logging.c b/pceplib/pcep_utils_logging.c
index 0286c2307..c9b2588b4 100644
--- a/pceplib/pcep_utils_logging.c
+++ b/pceplib/pcep_utils_logging.c
@@ -45,7 +45,7 @@ void set_logging_level(int level)
logging_level_ = level;
}
-int get_logging_level()
+int get_logging_level(void)
{
return logging_level_;
}
diff --git a/pceplib/pcep_utils_memory.c b/pceplib/pcep_utils_memory.c
index c564705f6..10856cac2 100644
--- a/pceplib/pcep_utils_memory.c
+++ b/pceplib/pcep_utils_memory.c
@@ -75,7 +75,7 @@ bool pceplib_memory_initialize(void *pceplib_infra_mt,
return true;
}
-void pceplib_memory_reset()
+void pceplib_memory_reset(void)
{
pceplib_infra_mt.total_bytes_allocated = 0;
pceplib_infra_mt.num_allocates = 0;
@@ -88,7 +88,7 @@ void pceplib_memory_reset()
pceplib_messages_mt.num_frees = 0;
}
-void pceplib_memory_dump()
+void pceplib_memory_dump(void)
{
if (PCEPLIB_INFRA) {
pcep_log(
diff --git a/pceplib/pcep_utils_queue.c b/pceplib/pcep_utils_queue.c
index 627533d01..22e417111 100644
--- a/pceplib/pcep_utils_queue.c
+++ b/pceplib/pcep_utils_queue.c
@@ -33,7 +33,7 @@
#include "pcep_utils_memory.h"
#include "pcep_utils_queue.h"
-queue_handle *queue_initialize()
+queue_handle *queue_initialize(void)
{
/* Set the max_entries to 0 to disable it */
return queue_initialize_with_size(0);
diff --git a/pimd/pim6_cmd.c b/pimd/pim6_cmd.c
index 49248798b..bd6d22947 100644
--- a/pimd/pim6_cmd.c
+++ b/pimd/pim6_cmd.c
@@ -45,9 +45,7 @@
#include "pim_zebra.h"
#include "pim_instance.h"
-#ifndef VTYSH_EXTRACT_PL
#include "pimd/pim6_cmd_clippy.c"
-#endif
static struct cmd_node debug_node = {
.name = "debug",
@@ -476,6 +474,47 @@ DEFPY (no_ipv6_pim_rp_prefix_list,
return pim_process_no_rp_plist_cmd(vty, rp_str, plist);
}
+DEFPY (ipv6_pim_bsm,
+ ipv6_pim_bsm_cmd,
+ "ipv6 pim bsm",
+ IPV6_STR
+ PIM_STR
+ "Enable BSM support on the interface\n")
+{
+ return pim_process_bsm_cmd(vty);
+}
+
+DEFPY (no_ipv6_pim_bsm,
+ no_ipv6_pim_bsm_cmd,
+ "no ipv6 pim bsm",
+ NO_STR
+ IPV6_STR
+ PIM_STR
+ "Enable BSM support on the interface\n")
+{
+ return pim_process_no_bsm_cmd(vty);
+}
+
+DEFPY (ipv6_pim_ucast_bsm,
+ ipv6_pim_ucast_bsm_cmd,
+ "ipv6 pim unicast-bsm",
+ IPV6_STR
+ PIM_STR
+ "Accept/Send unicast BSM on the interface\n")
+{
+ return pim_process_unicast_bsm_cmd(vty);
+}
+
+DEFPY (no_ipv6_pim_ucast_bsm,
+ no_ipv6_pim_ucast_bsm_cmd,
+ "no ipv6 pim unicast-bsm",
+ NO_STR
+ IPV6_STR
+ PIM_STR
+ "Accept/Send unicast BSM on the interface\n")
+{
+ return pim_process_no_unicast_bsm_cmd(vty);
+}
DEFPY (ipv6_ssmpingd,
ipv6_ssmpingd_cmd,
@@ -1240,6 +1279,44 @@ DEFPY (show_ipv6_pim_interface_traffic,
return pim_show_interface_traffic_helper(vrf, if_name, vty, !!json);
}
+DEFPY (show_ipv6_pim_bsr,
+ show_ipv6_pim_bsr_cmd,
+ "show ipv6 pim bsr [vrf NAME] [json$json]",
+ SHOW_STR
+ IPV6_STR
+ PIM_STR
+ "boot-strap router information\n"
+ VRF_CMD_HELP_STR
+ JSON_STR)
+{
+ return pim_show_bsr_helper(vrf, vty, !!json);
+}
+
+DEFPY (show_ipv6_pim_bsm_db,
+ show_ipv6_pim_bsm_db_cmd,
+ "show ipv6 pim bsm-database [vrf NAME] [json$json]",
+ SHOW_STR
+ IPV6_STR
+ PIM_STR
+ "PIM cached bsm packets information\n"
+ VRF_CMD_HELP_STR
+ JSON_STR)
+{
+ return pim_show_bsm_db_helper(vrf, vty, !!json);
+}
+
+DEFPY (show_ipv6_pim_bsrp,
+ show_ipv6_pim_bsrp_cmd,
+ "show ipv6 pim bsrp-info [vrf NAME] [json$json]",
+ SHOW_STR
+ IPV6_STR
+ PIM_STR
+ "PIM cached group-rp mappings information\n"
+ VRF_CMD_HELP_STR
+ JSON_STR)
+{
+ return pim_show_group_rp_mappings_info_helper(vrf, vty, !!json);
+}
DEFPY (clear_ipv6_pim_statistics,
clear_ipv6_pim_statistics_cmd,
@@ -1558,6 +1635,8 @@ DEFUN_NOSH (show_debugging_pimv6,
pim_debug_config_write(vty);
+ cmd_show_lib_debugs(vty);
+
return CMD_SUCCESS;
}
@@ -1646,6 +1725,22 @@ DEFPY (debug_mld_trace_detail,
return CMD_SUCCESS;
}
+DEFPY (debug_pimv6_bsm,
+ debug_pimv6_bsm_cmd,
+ "[no] debug pimv6 bsm",
+ NO_STR
+ DEBUG_STR
+ DEBUG_PIMV6_STR
+ DEBUG_PIMV6_BSM_STR)
+{
+ if (!no)
+ PIM_DO_DEBUG_BSM;
+ else
+ PIM_DONT_DEBUG_BSM;
+
+ return CMD_SUCCESS;
+}
+
void pim_cmd_init(void)
{
if_cmd_init(pim_interface_config_write);
@@ -1683,6 +1778,11 @@ void pim_cmd_init(void)
&interface_no_ipv6_pim_boundary_oil_cmd);
install_element(INTERFACE_NODE, &interface_ipv6_mroute_cmd);
install_element(INTERFACE_NODE, &interface_no_ipv6_mroute_cmd);
+ /* Install BSM command */
+ install_element(INTERFACE_NODE, &ipv6_pim_bsm_cmd);
+ install_element(INTERFACE_NODE, &no_ipv6_pim_bsm_cmd);
+ install_element(INTERFACE_NODE, &ipv6_pim_ucast_bsm_cmd);
+ install_element(INTERFACE_NODE, &no_ipv6_pim_ucast_bsm_cmd);
install_element(CONFIG_NODE, &ipv6_pim_rp_cmd);
install_element(VRF_NODE, &ipv6_pim_rp_cmd);
install_element(CONFIG_NODE, &no_ipv6_pim_rp_cmd);
@@ -1755,7 +1855,9 @@ void pim_cmd_init(void)
install_element(VIEW_NODE, &show_ipv6_mroute_summary_cmd);
install_element(VIEW_NODE, &show_ipv6_mroute_summary_vrf_all_cmd);
install_element(VIEW_NODE, &show_ipv6_pim_interface_traffic_cmd);
-
+ install_element(VIEW_NODE, &show_ipv6_pim_bsr_cmd);
+ install_element(VIEW_NODE, &show_ipv6_pim_bsm_db_cmd);
+ install_element(VIEW_NODE, &show_ipv6_pim_bsrp_cmd);
install_element(ENABLE_NODE, &clear_ipv6_pim_statistics_cmd);
install_element(ENABLE_NODE, &clear_ipv6_mroute_cmd);
install_element(ENABLE_NODE, &clear_ipv6_pim_oil_cmd);
@@ -1783,6 +1885,7 @@ void pim_cmd_init(void)
install_element(ENABLE_NODE, &debug_mld_packets_cmd);
install_element(ENABLE_NODE, &debug_mld_trace_cmd);
install_element(ENABLE_NODE, &debug_mld_trace_detail_cmd);
+ install_element(ENABLE_NODE, &debug_pimv6_bsm_cmd);
install_element(CONFIG_NODE, &debug_pimv6_cmd);
install_element(CONFIG_NODE, &debug_pimv6_nht_cmd);
@@ -1801,4 +1904,5 @@ void pim_cmd_init(void)
install_element(CONFIG_NODE, &debug_mld_packets_cmd);
install_element(CONFIG_NODE, &debug_mld_trace_cmd);
install_element(CONFIG_NODE, &debug_mld_trace_detail_cmd);
+ install_element(CONFIG_NODE, &debug_pimv6_bsm_cmd);
}
diff --git a/pimd/pim6_cmd.h b/pimd/pim6_cmd.h
index c45c99845..d9ff2ca70 100644
--- a/pimd/pim6_cmd.h
+++ b/pimd/pim6_cmd.h
@@ -58,6 +58,7 @@
#define DEBUG_PIMV6_TRACE_STR "PIMv6 internal daemon activity\n"
#define DEBUG_PIMV6_ZEBRA_STR "ZEBRA protocol activity\n"
#define DEBUG_MROUTE6_STR "PIMv6 interaction with kernel MFC cache\n"
+#define DEBUG_PIMV6_BSM_STR "BSR message processing activity\n"
void pim_cmd_init(void);
diff --git a/pimd/pim6_mld.c b/pimd/pim6_mld.c
index 23042ef14..dc5e67e2c 100644
--- a/pimd/pim6_mld.c
+++ b/pimd/pim6_mld.c
@@ -2319,9 +2319,7 @@ void gm_ifp_update(struct interface *ifp)
#include "lib/command.h"
-#ifndef VTYSH_EXTRACT_PL
#include "pimd/pim6_mld_clippy.c"
-#endif
static struct vrf *gm_cmd_vrf_lookup(struct vty *vty, const char *vrf_str,
int *err)
@@ -2997,9 +2995,9 @@ DEFPY(gm_debug_show,
"debug show mld interface IFNAME",
DEBUG_STR
SHOW_STR
- "MLD"
+ MLD_STR
INTERFACE_STR
- "interface name")
+ "interface name\n")
{
struct interface *ifp;
struct pim_interface *pim_ifp;
diff --git a/pimd/pim_br.c b/pimd/pim_br.c
deleted file mode 100644
index 6ec6b11e7..000000000
--- a/pimd/pim_br.c
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * PIM for Quagga
- * Copyright (C) 2015 Cumulus Networks, Inc.
- * Donald Sharp
- *
- * 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 "memory.h"
-#include "log.h"
-#include "if.h"
-
-#include "pimd.h"
-#include "pim_str.h"
-#include "pim_br.h"
-#include "linklist.h"
-
-struct pim_br {
- pim_sgaddr sg;
- pim_addr pmbr;
-};
-
-static struct list *pim_br_list = NULL;
-
-pim_addr pim_br_get_pmbr(pim_sgaddr *sg)
-{
- struct listnode *node;
- struct pim_br *pim_br;
-
- for (ALL_LIST_ELEMENTS_RO(pim_br_list, node, pim_br)) {
- if (!pim_sgaddr_cmp(*sg, pim_br->sg))
- return pim_br->pmbr;
- }
-
- return PIMADDR_ANY;
-}
-
-void pim_br_set_pmbr(pim_sgaddr *sg, pim_addr br)
-{
- struct listnode *node, *next;
- struct pim_br *pim_br;
-
- for (ALL_LIST_ELEMENTS(pim_br_list, node, next, pim_br)) {
- if (!pim_sgaddr_cmp(*sg, pim_br->sg))
- break;
- }
-
- if (!pim_br) {
- pim_br = XCALLOC(MTYPE_PIM_BR, sizeof(*pim_br));
- pim_br->sg = *sg;
-
- listnode_add(pim_br_list, pim_br);
- }
-
- pim_br->pmbr = br;
-}
-
-/*
- * Remove the (S,G) from the stored values
- */
-void pim_br_clear_pmbr(pim_sgaddr *sg)
-{
- struct listnode *node, *next;
- struct pim_br *pim_br;
-
- for (ALL_LIST_ELEMENTS(pim_br_list, node, next, pim_br)) {
- if (!pim_sgaddr_cmp(*sg, pim_br->sg))
- break;
- }
-
- if (!pim_br)
- return;
-
- listnode_delete(pim_br_list, pim_br);
-}
-
-void pim_br_init(void)
-{
- pim_br_list = list_new();
-}
diff --git a/pimd/pim_br.h b/pimd/pim_br.h
deleted file mode 100644
index 7b87c0f1f..000000000
--- a/pimd/pim_br.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * PIM for Quagga
- * Copyright (C) 2015 Cumulus Networks, Inc.
- * Donald Sharp
- *
- * 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 PIM_BR_H
-#define PIM_BR_H
-
-pim_addr pim_br_get_pmbr(pim_sgaddr *sg);
-
-void pim_br_set_pmbr(pim_sgaddr *sg, pim_addr value);
-void pim_br_clear_pmbr(pim_sgaddr *sg);
-
-void pim_br_init(void);
-
-#endif
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index c2f7396c1..306891c0e 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -70,9 +70,7 @@
#include "pim_addr.h"
#include "pim_cmd_common.h"
-#ifndef VTYSH_EXTRACT_PL
#include "pimd/pim_cmd_clippy.c"
-#endif
static struct cmd_node debug_node = {
.name = "debug",
@@ -837,285 +835,6 @@ static void igmp_show_statistics(struct pim_instance *pim, struct vty *vty,
}
}
-/* Display the bsm database details */
-static void pim_show_bsm_db(struct pim_instance *pim, struct vty *vty, bool uj)
-{
- int count = 0;
- int fragment = 1;
- struct bsm_frag *bsfrag;
- json_object *json = NULL;
- json_object *json_group = NULL;
- json_object *json_row = NULL;
-
- count = bsm_frags_count(pim->global_scope.bsm_frags);
-
- if (uj) {
- json = json_object_new_object();
- json_object_int_add(json, "Number of the fragments", count);
- } else {
- vty_out(vty, "Scope Zone: Global\n");
- vty_out(vty, "Number of the fragments: %d\n", count);
- vty_out(vty, "\n");
- }
-
- frr_each (bsm_frags, pim->global_scope.bsm_frags, bsfrag) {
- char grp_str[PREFIX_STRLEN];
- struct bsmmsg_grpinfo *group;
- struct bsmmsg_rpinfo *bsm_rpinfo;
- struct prefix grp;
- struct bsm_hdr *hdr;
- pim_addr bsr_addr;
- uint32_t offset = 0;
- uint8_t *buf;
- uint32_t len = 0;
- uint32_t frag_rp_cnt = 0;
-
- buf = bsfrag->data;
- len = bsfrag->size;
-
- /* skip pim header */
- buf += PIM_MSG_HEADER_LEN;
- len -= PIM_MSG_HEADER_LEN;
-
- hdr = (struct bsm_hdr *)buf;
- /* NB: bshdr->bsr_addr.addr is packed/unaligned => memcpy */
- memcpy(&bsr_addr, &hdr->bsr_addr.addr, sizeof(bsr_addr));
-
- /* BSM starts with bsr header */
- buf += sizeof(struct bsm_hdr);
- len -= sizeof(struct bsm_hdr);
-
- if (uj) {
- json_object_string_addf(json, "BSR address", "%pPA",
- &bsr_addr);
- json_object_int_add(json, "BSR priority",
- hdr->bsr_prio);
- json_object_int_add(json, "Hashmask Length",
- hdr->hm_len);
- json_object_int_add(json, "Fragment Tag",
- ntohs(hdr->frag_tag));
- } else {
- vty_out(vty, "BSM Fragment : %d\n", fragment);
- vty_out(vty, "------------------\n");
- vty_out(vty, "%-15s %-15s %-15s %-15s\n", "BSR-Address",
- "BSR-Priority", "Hashmask-len", "Fragment-Tag");
- vty_out(vty, "%-15pPA %-15d %-15d %-15d\n", &bsr_addr,
- hdr->bsr_prio, hdr->hm_len,
- ntohs(hdr->frag_tag));
- }
-
- vty_out(vty, "\n");
-
- while (offset < len) {
- group = (struct bsmmsg_grpinfo *)buf;
-
- if (group->group.family == PIM_MSG_ADDRESS_FAMILY_IPV4)
- grp.family = AF_INET;
- else if (group->group.family ==
- PIM_MSG_ADDRESS_FAMILY_IPV6)
- grp.family = AF_INET6;
-
- grp.prefixlen = group->group.mask;
-#if PIM_IPV == 4
- grp.u.prefix4 = group->group.addr;
-#else
- grp.u.prefix6 = group->group.addr;
-#endif
-
- prefix2str(&grp, grp_str, sizeof(grp_str));
-
- buf += sizeof(struct bsmmsg_grpinfo);
- offset += sizeof(struct bsmmsg_grpinfo);
-
- if (uj) {
- json_object_object_get_ex(json, grp_str,
- &json_group);
- if (!json_group) {
- json_group = json_object_new_object();
- json_object_int_add(json_group,
- "Rp Count",
- group->rp_count);
- json_object_int_add(
- json_group, "Fragment Rp count",
- group->frag_rp_count);
- json_object_object_add(json, grp_str,
- json_group);
- }
- } else {
- vty_out(vty, "Group : %s\n", grp_str);
- vty_out(vty, "-------------------\n");
- vty_out(vty, "Rp Count:%d\n", group->rp_count);
- vty_out(vty, "Fragment Rp Count : %d\n",
- group->frag_rp_count);
- }
-
- frag_rp_cnt = group->frag_rp_count;
-
- if (!frag_rp_cnt)
- continue;
-
- if (!uj)
- vty_out(vty,
- "RpAddress HoldTime Priority\n");
-
- while (frag_rp_cnt--) {
- pim_addr rp_addr;
-
- bsm_rpinfo = (struct bsmmsg_rpinfo *)buf;
- /* unaligned, again */
- memcpy(&rp_addr, &bsm_rpinfo->rpaddr,
- sizeof(rp_addr));
-
- buf += sizeof(struct bsmmsg_rpinfo);
- offset += sizeof(struct bsmmsg_rpinfo);
-
- if (uj) {
- json_row = json_object_new_object();
- json_object_string_addf(
- json_row, "Rp Address", "%pPA",
- &rp_addr);
- json_object_int_add(
- json_row, "Rp HoldTime",
- ntohs(bsm_rpinfo->rp_holdtime));
- json_object_int_add(json_row,
- "Rp Priority",
- bsm_rpinfo->rp_pri);
- json_object_object_addf(
- json_group, json_row, "%pPA",
- &rp_addr);
- } else {
- vty_out(vty, "%-15pPA %-12d %d\n",
- &rp_addr,
- ntohs(bsm_rpinfo->rp_holdtime),
- bsm_rpinfo->rp_pri);
- }
- }
- vty_out(vty, "\n");
- }
-
- fragment++;
- }
-
- if (uj)
- vty_json(vty, json);
-}
-
-/*Display the group-rp mappings */
-static void pim_show_group_rp_mappings_info(struct pim_instance *pim,
- struct vty *vty, bool uj)
-{
- struct bsgrp_node *bsgrp;
- struct bsm_rpinfo *bsm_rp;
- struct route_node *rn;
- json_object *json = NULL;
- json_object *json_group = NULL;
- json_object *json_row = NULL;
-
- if (uj) {
- json = json_object_new_object();
- json_object_string_addf(json, "BSR Address", "%pPA",
- &pim->global_scope.current_bsr);
- } else
- vty_out(vty, "BSR Address %pPA\n",
- &pim->global_scope.current_bsr);
-
- for (rn = route_top(pim->global_scope.bsrp_table); rn;
- rn = route_next(rn)) {
- bsgrp = (struct bsgrp_node *)rn->info;
-
- if (!bsgrp)
- continue;
-
- char grp_str[PREFIX_STRLEN];
-
- prefix2str(&bsgrp->group, grp_str, sizeof(grp_str));
-
- if (uj) {
- json_object_object_get_ex(json, grp_str, &json_group);
- if (!json_group) {
- json_group = json_object_new_object();
- json_object_object_add(json, grp_str,
- json_group);
- }
- } else {
- vty_out(vty, "Group Address %pFX\n", &bsgrp->group);
- vty_out(vty, "--------------------------\n");
- vty_out(vty, "%-15s %-15s %-15s %-15s\n", "Rp Address",
- "priority", "Holdtime", "Hash");
-
- vty_out(vty, "(ACTIVE)\n");
- }
-
- frr_each (bsm_rpinfos, bsgrp->bsrp_list, bsm_rp) {
- if (uj) {
- json_row = json_object_new_object();
- json_object_string_addf(json_row, "Rp Address",
- "%pPA",
- &bsm_rp->rp_address);
- json_object_int_add(json_row, "Rp HoldTime",
- bsm_rp->rp_holdtime);
- json_object_int_add(json_row, "Rp Priority",
- bsm_rp->rp_prio);
- json_object_int_add(json_row, "Hash Val",
- bsm_rp->hash);
- json_object_object_addf(json_group, json_row,
- "%pPA",
- &bsm_rp->rp_address);
-
- } else {
- vty_out(vty, "%-15pPA %-15u %-15u %-15u\n",
- &bsm_rp->rp_address, bsm_rp->rp_prio,
- bsm_rp->rp_holdtime, bsm_rp->hash);
- }
- }
- if (!bsm_rpinfos_count(bsgrp->bsrp_list) && !uj)
- vty_out(vty, "Active List is empty.\n");
-
- if (uj) {
- json_object_int_add(json_group, "Pending RP count",
- bsgrp->pend_rp_cnt);
- } else {
- vty_out(vty, "(PENDING)\n");
- vty_out(vty, "Pending RP count :%d\n",
- bsgrp->pend_rp_cnt);
- if (bsgrp->pend_rp_cnt)
- vty_out(vty, "%-15s %-15s %-15s %-15s\n",
- "Rp Address", "priority", "Holdtime",
- "Hash");
- }
-
- frr_each (bsm_rpinfos, bsgrp->partial_bsrp_list, bsm_rp) {
- if (uj) {
- json_row = json_object_new_object();
- json_object_string_addf(json_row, "Rp Address",
- "%pPA",
- &bsm_rp->rp_address);
- json_object_int_add(json_row, "Rp HoldTime",
- bsm_rp->rp_holdtime);
- json_object_int_add(json_row, "Rp Priority",
- bsm_rp->rp_prio);
- json_object_int_add(json_row, "Hash Val",
- bsm_rp->hash);
- json_object_object_addf(json_group, json_row,
- "%pPA",
- &bsm_rp->rp_address);
- } else {
- vty_out(vty, "%-15pPA %-15u %-15u %-15u\n",
- &bsm_rp->rp_address, bsm_rp->rp_prio,
- bsm_rp->rp_holdtime, bsm_rp->hash);
- }
- }
- if (!bsm_rpinfos_count(bsgrp->partial_bsrp_list) && !uj)
- vty_out(vty, "Partial List is empty\n");
-
- if (!uj)
- vty_out(vty, "\n");
- }
-
- if (uj)
- vty_json(vty, json);
-}
-
static void igmp_show_groups(struct pim_instance *pim, struct vty *vty, bool uj)
{
struct interface *ifp;
@@ -1439,77 +1158,6 @@ static void igmp_show_source_retransmission(struct pim_instance *pim,
} /* scan interfaces */
}
-static void pim_show_bsr(struct pim_instance *pim,
- struct vty *vty,
- bool uj)
-{
- char uptime[10];
- char last_bsm_seen[10];
- time_t now;
- char bsr_state[20];
- json_object *json = NULL;
-
- if (pim_addr_is_any(pim->global_scope.current_bsr)) {
- pim_time_uptime(uptime, sizeof(uptime),
- pim->global_scope.current_bsr_first_ts);
- pim_time_uptime(last_bsm_seen, sizeof(last_bsm_seen),
- pim->global_scope.current_bsr_last_ts);
- }
-
- else {
- now = pim_time_monotonic_sec();
- pim_time_uptime(uptime, sizeof(uptime),
- (now - pim->global_scope.current_bsr_first_ts));
- pim_time_uptime(last_bsm_seen, sizeof(last_bsm_seen),
- now - pim->global_scope.current_bsr_last_ts);
- }
-
- switch (pim->global_scope.state) {
- case NO_INFO:
- strlcpy(bsr_state, "NO_INFO", sizeof(bsr_state));
- break;
- case ACCEPT_ANY:
- strlcpy(bsr_state, "ACCEPT_ANY", sizeof(bsr_state));
- break;
- case ACCEPT_PREFERRED:
- strlcpy(bsr_state, "ACCEPT_PREFERRED", sizeof(bsr_state));
- break;
- default:
- strlcpy(bsr_state, "", sizeof(bsr_state));
- }
-
-
- if (uj) {
- json = json_object_new_object();
- json_object_string_addf(json, "bsr", "%pPA",
- &pim->global_scope.current_bsr);
- json_object_int_add(json, "priority",
- pim->global_scope.current_bsr_prio);
- json_object_int_add(json, "fragmentTag",
- pim->global_scope.bsm_frag_tag);
- json_object_string_add(json, "state", bsr_state);
- json_object_string_add(json, "upTime", uptime);
- json_object_string_add(json, "lastBsmSeen", last_bsm_seen);
- }
-
- else {
- vty_out(vty, "PIMv2 Bootstrap information\n");
- vty_out(vty, "Current preferred BSR address: %pPA\n",
- &pim->global_scope.current_bsr);
- vty_out(vty,
- "Priority Fragment-Tag State UpTime\n");
- vty_out(vty, " %-12d %-12d %-13s %7s\n",
- pim->global_scope.current_bsr_prio,
- pim->global_scope.bsm_frag_tag,
- bsr_state,
- uptime);
- vty_out(vty, "Last BSM seen: %s\n", last_bsm_seen);
- }
-
- if (uj)
- vty_json(vty, json);
-}
-
static void clear_igmp_interfaces(struct pim_instance *pim)
{
struct interface *ifp;
@@ -2772,9 +2420,9 @@ DEFPY (show_ip_pim_interface_traffic,
return pim_show_interface_traffic_helper(vrf, if_name, vty, !!json);
}
-DEFUN (show_ip_pim_bsm_db,
+DEFPY (show_ip_pim_bsm_db,
show_ip_pim_bsm_db_cmd,
- "show ip pim bsm-database [vrf NAME] [json]",
+ "show ip pim bsm-database [vrf NAME] [json$json]",
SHOW_STR
IP_STR
PIM_STR
@@ -2782,20 +2430,12 @@ DEFUN (show_ip_pim_bsm_db,
VRF_CMD_HELP_STR
JSON_STR)
{
- int idx = 2;
- struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
- bool uj = use_json(argc, argv);
-
- if (!vrf)
- return CMD_WARNING;
-
- pim_show_bsm_db(vrf->info, vty, uj);
- return CMD_SUCCESS;
+ return pim_show_bsm_db_helper(vrf, vty, !!json);
}
-DEFUN (show_ip_pim_bsrp,
+DEFPY (show_ip_pim_bsrp,
show_ip_pim_bsrp_cmd,
- "show ip pim bsrp-info [vrf NAME] [json]",
+ "show ip pim bsrp-info [vrf NAME] [json$json]",
SHOW_STR
IP_STR
PIM_STR
@@ -2803,16 +2443,7 @@ DEFUN (show_ip_pim_bsrp,
VRF_CMD_HELP_STR
JSON_STR)
{
- int idx = 2;
- struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
- bool uj = use_json(argc, argv);
-
- if (!vrf)
- return CMD_WARNING;
-
- pim_show_group_rp_mappings_info(vrf->info, vty, uj);
-
- return CMD_SUCCESS;
+ return pim_show_group_rp_mappings_info_helper(vrf, vty, !!json);
}
DEFPY (show_ip_pim_statistics,
@@ -3586,25 +3217,17 @@ DEFUN (show_ip_pim_group_type,
return CMD_SUCCESS;
}
-DEFUN (show_ip_pim_bsr,
+DEFPY (show_ip_pim_bsr,
show_ip_pim_bsr_cmd,
- "show ip pim bsr [json]",
+ "show ip pim bsr [vrf NAME] [json$json]",
SHOW_STR
IP_STR
PIM_STR
"boot-strap router information\n"
+ VRF_CMD_HELP_STR
JSON_STR)
{
- int idx = 2;
- struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx);
- bool uj = use_json(argc, argv);
-
- if (!vrf)
- return CMD_WARNING;
-
- pim_show_bsr(vrf->info, vty, uj);
-
- return CMD_SUCCESS;
+ return pim_show_bsr_helper(vrf, vty, !!json);
}
DEFUN (ip_ssmpingd,
@@ -4906,6 +4529,7 @@ DEFUN_NOSH (show_debugging_pim,
pim_debug_config_write(vty);
+ cmd_show_lib_debugs(vty);
return CMD_SUCCESS;
}
@@ -5009,41 +4633,19 @@ DEFUN (ip_pim_bsm,
"ip pim bsm",
IP_STR
PIM_STR
- "Enables BSM support on the interface\n")
+ "Enable BSM support on the interface\n")
{
- const struct lyd_node *igmp_enable_dnode;
-
- igmp_enable_dnode =
- yang_dnode_getf(vty->candidate_config->dnode,
- FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH,
- "frr-routing:ipv4");
- if (!igmp_enable_dnode)
- nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
- "true");
- else {
- if (!yang_dnode_get_bool(igmp_enable_dnode, "."))
- nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
- "true");
- }
-
- nb_cli_enqueue_change(vty, "./bsm", NB_OP_MODIFY, "true");
-
- return nb_cli_apply_changes(vty,
- FRR_PIM_INTERFACE_XPATH, "frr-routing:ipv4");
+ return pim_process_bsm_cmd(vty);
}
-
DEFUN (no_ip_pim_bsm,
no_ip_pim_bsm_cmd,
"no ip pim bsm",
NO_STR
IP_STR
PIM_STR
- "Disables BSM support\n")
+ "Enable BSM support on the interface\n")
{
- nb_cli_enqueue_change(vty, "./bsm", NB_OP_MODIFY, "false");
-
- return nb_cli_apply_changes(vty,
- FRR_PIM_INTERFACE_XPATH, "frr-routing:ipv4");
+ return pim_process_no_bsm_cmd(vty);
}
DEFUN (ip_pim_ucast_bsm,
@@ -5053,26 +4655,7 @@ DEFUN (ip_pim_ucast_bsm,
PIM_STR
"Accept/Send unicast BSM on the interface\n")
{
- const struct lyd_node *igmp_enable_dnode;
-
- igmp_enable_dnode =
- yang_dnode_getf(vty->candidate_config->dnode,
- FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH,
- "frr-routing:ipv4");
- if (!igmp_enable_dnode)
- nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
- "true");
- else {
- if (!yang_dnode_get_bool(igmp_enable_dnode, "."))
- nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
- "true");
- }
-
- nb_cli_enqueue_change(vty, "./unicast-bsm", NB_OP_MODIFY, "true");
-
- return nb_cli_apply_changes(vty,
- FRR_PIM_INTERFACE_XPATH, "frr-routing:ipv4");
-
+ return pim_process_unicast_bsm_cmd(vty);
}
DEFUN (no_ip_pim_ucast_bsm,
@@ -5081,12 +4664,9 @@ DEFUN (no_ip_pim_ucast_bsm,
NO_STR
IP_STR
PIM_STR
- "Block send/receive unicast BSM on this interface\n")
+ "Accept/Send unicast BSM on the interface\n")
{
- nb_cli_enqueue_change(vty, "./unicast-bsm", NB_OP_MODIFY, "false");
-
- return nb_cli_apply_changes(vty,
- FRR_PIM_INTERFACE_XPATH, "frr-routing:ipv4");
+ return pim_process_no_unicast_bsm_cmd(vty);
}
#if HAVE_BFDD > 0
@@ -5437,7 +5017,7 @@ DEFPY(no_ip_msdp_mesh_group,
IP_STR
CFG_MSDP_STR
"Delete MSDP mesh-group\n"
- "Mesh group name")
+ "Mesh group name\n")
{
const char *vrfname;
char xpath_value[XPATH_MAXLEN];
diff --git a/pimd/pim_cmd_common.c b/pimd/pim_cmd_common.c
index 9283016d0..b39f688cd 100644
--- a/pimd/pim_cmd_common.c
+++ b/pimd/pim_cmd_common.c
@@ -566,6 +566,18 @@ int pim_process_rp_cmd(struct vty *vty, const char *rp_str,
return CMD_WARNING_CONFIG_FAILED;
}
+ if (pim_addr_is_any(rp_addr) || pim_addr_is_multicast(rp_addr)) {
+ vty_out(vty, "%% Bad RP address specified: %s\n", rp_str);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+#if PIM_IPV == 6
+ if (IN6_IS_ADDR_LINKLOCAL(&rp_addr)) {
+ vty_out(vty, "%% Bad RP address specified: %s\n", rp_str);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+#endif
+
vrfname = pim_cli_get_vrf_name(vty);
if (vrfname == NULL)
return CMD_WARNING_CONFIG_FAILED;
@@ -3416,6 +3428,66 @@ int pim_process_ssmpingd_cmd(struct vty *vty, enum nb_operation operation,
return nb_cli_apply_changes(vty, NULL);
}
+int pim_process_bsm_cmd(struct vty *vty)
+{
+ const struct lyd_node *gm_enable_dnode;
+
+ gm_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode,
+ FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH,
+ FRR_PIM_AF_XPATH_VAL);
+ if (!gm_enable_dnode)
+ nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
+ "true");
+ else {
+ if (!yang_dnode_get_bool(gm_enable_dnode, "."))
+ nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
+ "true");
+ }
+
+ nb_cli_enqueue_change(vty, "./bsm", NB_OP_MODIFY, "true");
+
+ return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
+ FRR_PIM_AF_XPATH_VAL);
+}
+
+int pim_process_no_bsm_cmd(struct vty *vty)
+{
+ nb_cli_enqueue_change(vty, "./bsm", NB_OP_MODIFY, "false");
+
+ return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
+ FRR_PIM_AF_XPATH_VAL);
+}
+
+int pim_process_unicast_bsm_cmd(struct vty *vty)
+{
+ const struct lyd_node *gm_enable_dnode;
+
+ gm_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode,
+ FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH,
+ FRR_PIM_AF_XPATH_VAL);
+ if (!gm_enable_dnode)
+ nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
+ "true");
+ else {
+ if (!yang_dnode_get_bool(gm_enable_dnode, "."))
+ nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY,
+ "true");
+ }
+
+ nb_cli_enqueue_change(vty, "./unicast-bsm", NB_OP_MODIFY, "true");
+
+ return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
+ FRR_PIM_AF_XPATH_VAL);
+}
+
+int pim_process_no_unicast_bsm_cmd(struct vty *vty)
+{
+ nb_cli_enqueue_change(vty, "./unicast-bsm", NB_OP_MODIFY, "false");
+
+ return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH,
+ FRR_PIM_AF_XPATH_VAL);
+}
+
static void show_scan_oil_stats(struct pim_instance *pim, struct vty *vty,
time_t now)
{
@@ -5183,3 +5255,416 @@ void clear_pim_interfaces(struct pim_instance *pim)
pim_neighbor_delete_all(ifp, "interface cleared");
}
}
+
+void pim_show_bsr(struct pim_instance *pim, struct vty *vty, bool uj)
+{
+ char uptime[10];
+ char last_bsm_seen[10];
+ time_t now;
+ char bsr_state[20];
+ json_object *json = NULL;
+
+ if (pim_addr_is_any(pim->global_scope.current_bsr)) {
+ pim_time_uptime(uptime, sizeof(uptime),
+ pim->global_scope.current_bsr_first_ts);
+ pim_time_uptime(last_bsm_seen, sizeof(last_bsm_seen),
+ pim->global_scope.current_bsr_last_ts);
+ }
+
+ else {
+ now = pim_time_monotonic_sec();
+ pim_time_uptime(uptime, sizeof(uptime),
+ (now - pim->global_scope.current_bsr_first_ts));
+ pim_time_uptime(last_bsm_seen, sizeof(last_bsm_seen),
+ now - pim->global_scope.current_bsr_last_ts);
+ }
+
+ switch (pim->global_scope.state) {
+ case NO_INFO:
+ strlcpy(bsr_state, "NO_INFO", sizeof(bsr_state));
+ break;
+ case ACCEPT_ANY:
+ strlcpy(bsr_state, "ACCEPT_ANY", sizeof(bsr_state));
+ break;
+ case ACCEPT_PREFERRED:
+ strlcpy(bsr_state, "ACCEPT_PREFERRED", sizeof(bsr_state));
+ break;
+ default:
+ strlcpy(bsr_state, "", sizeof(bsr_state));
+ }
+
+
+ if (uj) {
+ json = json_object_new_object();
+ json_object_string_addf(json, "bsr", "%pPA",
+ &pim->global_scope.current_bsr);
+ json_object_int_add(json, "priority",
+ pim->global_scope.current_bsr_prio);
+ json_object_int_add(json, "fragmentTag",
+ pim->global_scope.bsm_frag_tag);
+ json_object_string_add(json, "state", bsr_state);
+ json_object_string_add(json, "upTime", uptime);
+ json_object_string_add(json, "lastBsmSeen", last_bsm_seen);
+ }
+
+ else {
+ vty_out(vty, "PIMv2 Bootstrap information\n");
+ vty_out(vty, "Current preferred BSR address: %pPA\n",
+ &pim->global_scope.current_bsr);
+ vty_out(vty,
+ "Priority Fragment-Tag State UpTime\n");
+ vty_out(vty, " %-12d %-12d %-13s %7s\n",
+ pim->global_scope.current_bsr_prio,
+ pim->global_scope.bsm_frag_tag, bsr_state, uptime);
+ vty_out(vty, "Last BSM seen: %s\n", last_bsm_seen);
+ }
+
+ if (uj)
+ vty_json(vty, json);
+}
+
+int pim_show_bsr_helper(const char *vrf, struct vty *vty, bool uj)
+{
+ struct pim_instance *pim;
+ struct vrf *v;
+
+ v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
+
+ if (!v)
+ return CMD_WARNING;
+
+ pim = pim_get_pim_instance(v->vrf_id);
+
+ if (!pim) {
+ vty_out(vty, "%% Unable to find pim instance\n");
+ return CMD_WARNING;
+ }
+
+ pim_show_bsr(v->info, vty, uj);
+
+ return CMD_SUCCESS;
+}
+
+/*Display the group-rp mappings */
+static void pim_show_group_rp_mappings_info(struct pim_instance *pim,
+ struct vty *vty, bool uj)
+{
+ struct bsgrp_node *bsgrp;
+ struct bsm_rpinfo *bsm_rp;
+ struct route_node *rn;
+ json_object *json = NULL;
+ json_object *json_group = NULL;
+ json_object *json_row = NULL;
+
+ if (uj) {
+ json = json_object_new_object();
+ json_object_string_addf(json, "BSR Address", "%pPA",
+ &pim->global_scope.current_bsr);
+ } else
+ vty_out(vty, "BSR Address %pPA\n",
+ &pim->global_scope.current_bsr);
+
+ for (rn = route_top(pim->global_scope.bsrp_table); rn;
+ rn = route_next(rn)) {
+ bsgrp = (struct bsgrp_node *)rn->info;
+
+ if (!bsgrp)
+ continue;
+
+ char grp_str[PREFIX_STRLEN];
+
+ prefix2str(&bsgrp->group, grp_str, sizeof(grp_str));
+
+ if (uj) {
+ json_object_object_get_ex(json, grp_str, &json_group);
+ if (!json_group) {
+ json_group = json_object_new_object();
+ json_object_object_add(json, grp_str,
+ json_group);
+ }
+ } else {
+ vty_out(vty, "Group Address %pFX\n", &bsgrp->group);
+ vty_out(vty, "--------------------------\n");
+ vty_out(vty, "%-15s %-15s %-15s %-15s\n", "Rp Address",
+ "priority", "Holdtime", "Hash");
+
+ vty_out(vty, "(ACTIVE)\n");
+ }
+
+ frr_each (bsm_rpinfos, bsgrp->bsrp_list, bsm_rp) {
+ if (uj) {
+ json_row = json_object_new_object();
+ json_object_string_addf(json_row, "Rp Address",
+ "%pPA",
+ &bsm_rp->rp_address);
+ json_object_int_add(json_row, "Rp HoldTime",
+ bsm_rp->rp_holdtime);
+ json_object_int_add(json_row, "Rp Priority",
+ bsm_rp->rp_prio);
+ json_object_int_add(json_row, "Hash Val",
+ bsm_rp->hash);
+ json_object_object_addf(json_group, json_row,
+ "%pPA",
+ &bsm_rp->rp_address);
+
+ } else {
+ vty_out(vty, "%-15pPA %-15u %-15u %-15u\n",
+ &bsm_rp->rp_address, bsm_rp->rp_prio,
+ bsm_rp->rp_holdtime, bsm_rp->hash);
+ }
+ }
+ if (!bsm_rpinfos_count(bsgrp->bsrp_list) && !uj)
+ vty_out(vty, "Active List is empty.\n");
+
+ if (uj) {
+ json_object_int_add(json_group, "Pending RP count",
+ bsgrp->pend_rp_cnt);
+ } else {
+ vty_out(vty, "(PENDING)\n");
+ vty_out(vty, "Pending RP count :%d\n",
+ bsgrp->pend_rp_cnt);
+ if (bsgrp->pend_rp_cnt)
+ vty_out(vty, "%-15s %-15s %-15s %-15s\n",
+ "Rp Address", "priority", "Holdtime",
+ "Hash");
+ }
+
+ frr_each (bsm_rpinfos, bsgrp->partial_bsrp_list, bsm_rp) {
+ if (uj) {
+ json_row = json_object_new_object();
+ json_object_string_addf(json_row, "Rp Address",
+ "%pPA",
+ &bsm_rp->rp_address);
+ json_object_int_add(json_row, "Rp HoldTime",
+ bsm_rp->rp_holdtime);
+ json_object_int_add(json_row, "Rp Priority",
+ bsm_rp->rp_prio);
+ json_object_int_add(json_row, "Hash Val",
+ bsm_rp->hash);
+ json_object_object_addf(json_group, json_row,
+ "%pPA",
+ &bsm_rp->rp_address);
+ } else {
+ vty_out(vty, "%-15pPA %-15u %-15u %-15u\n",
+ &bsm_rp->rp_address, bsm_rp->rp_prio,
+ bsm_rp->rp_holdtime, bsm_rp->hash);
+ }
+ }
+ if (!bsm_rpinfos_count(bsgrp->partial_bsrp_list) && !uj)
+ vty_out(vty, "Partial List is empty\n");
+
+ if (!uj)
+ vty_out(vty, "\n");
+ }
+
+ if (uj)
+ vty_json(vty, json);
+}
+
+int pim_show_group_rp_mappings_info_helper(const char *vrf, struct vty *vty,
+ bool uj)
+{
+ struct pim_instance *pim;
+ struct vrf *v;
+
+ v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
+
+ if (!v)
+ return CMD_WARNING;
+
+ pim = v->info;
+
+ if (!pim) {
+ vty_out(vty, "%% Unable to find pim instance\n");
+ return CMD_WARNING;
+ }
+
+ pim_show_group_rp_mappings_info(v->info, vty, uj);
+
+ return CMD_SUCCESS;
+}
+
+/* Display the bsm database details */
+static void pim_show_bsm_db(struct pim_instance *pim, struct vty *vty, bool uj)
+{
+ int count = 0;
+ int fragment = 1;
+ struct bsm_frag *bsfrag;
+ json_object *json = NULL;
+ json_object *json_group = NULL;
+ json_object *json_row = NULL;
+
+ count = bsm_frags_count(pim->global_scope.bsm_frags);
+
+ if (uj) {
+ json = json_object_new_object();
+ json_object_int_add(json, "Number of the fragments", count);
+ } else {
+ vty_out(vty, "Scope Zone: Global\n");
+ vty_out(vty, "Number of the fragments: %d\n", count);
+ vty_out(vty, "\n");
+ }
+
+ frr_each (bsm_frags, pim->global_scope.bsm_frags, bsfrag) {
+ char grp_str[PREFIX_STRLEN];
+ struct bsmmsg_grpinfo *group;
+ struct bsmmsg_rpinfo *bsm_rpinfo;
+ struct prefix grp;
+ struct bsm_hdr *hdr;
+ pim_addr bsr_addr;
+ uint32_t offset = 0;
+ uint8_t *buf;
+ uint32_t len = 0;
+ uint32_t frag_rp_cnt = 0;
+
+ buf = bsfrag->data;
+ len = bsfrag->size;
+
+ /* skip pim header */
+ buf += PIM_MSG_HEADER_LEN;
+ len -= PIM_MSG_HEADER_LEN;
+
+ hdr = (struct bsm_hdr *)buf;
+ /* NB: bshdr->bsr_addr.addr is packed/unaligned => memcpy */
+ memcpy(&bsr_addr, &hdr->bsr_addr.addr, sizeof(bsr_addr));
+
+ /* BSM starts with bsr header */
+ buf += sizeof(struct bsm_hdr);
+ len -= sizeof(struct bsm_hdr);
+
+ if (uj) {
+ json_object_string_addf(json, "BSR address", "%pPA",
+ &bsr_addr);
+ json_object_int_add(json, "BSR priority",
+ hdr->bsr_prio);
+ json_object_int_add(json, "Hashmask Length",
+ hdr->hm_len);
+ json_object_int_add(json, "Fragment Tag",
+ ntohs(hdr->frag_tag));
+ } else {
+ vty_out(vty, "BSM Fragment : %d\n", fragment);
+ vty_out(vty, "------------------\n");
+ vty_out(vty, "%-15s %-15s %-15s %-15s\n", "BSR-Address",
+ "BSR-Priority", "Hashmask-len", "Fragment-Tag");
+ vty_out(vty, "%-15pPA %-15d %-15d %-15d\n", &bsr_addr,
+ hdr->bsr_prio, hdr->hm_len,
+ ntohs(hdr->frag_tag));
+ }
+
+ vty_out(vty, "\n");
+
+ while (offset < len) {
+ group = (struct bsmmsg_grpinfo *)buf;
+
+ if (group->group.family == PIM_MSG_ADDRESS_FAMILY_IPV4)
+ grp.family = AF_INET;
+ else if (group->group.family ==
+ PIM_MSG_ADDRESS_FAMILY_IPV6)
+ grp.family = AF_INET6;
+
+ grp.prefixlen = group->group.mask;
+#if PIM_IPV == 4
+ grp.u.prefix4 = group->group.addr;
+#else
+ grp.u.prefix6 = group->group.addr;
+#endif
+
+ prefix2str(&grp, grp_str, sizeof(grp_str));
+
+ buf += sizeof(struct bsmmsg_grpinfo);
+ offset += sizeof(struct bsmmsg_grpinfo);
+
+ if (uj) {
+ json_object_object_get_ex(json, grp_str,
+ &json_group);
+ if (!json_group) {
+ json_group = json_object_new_object();
+ json_object_int_add(json_group,
+ "Rp Count",
+ group->rp_count);
+ json_object_int_add(
+ json_group, "Fragment Rp count",
+ group->frag_rp_count);
+ json_object_object_add(json, grp_str,
+ json_group);
+ }
+ } else {
+ vty_out(vty, "Group : %s\n", grp_str);
+ vty_out(vty, "-------------------\n");
+ vty_out(vty, "Rp Count:%d\n", group->rp_count);
+ vty_out(vty, "Fragment Rp Count : %d\n",
+ group->frag_rp_count);
+ }
+
+ frag_rp_cnt = group->frag_rp_count;
+
+ if (!frag_rp_cnt)
+ continue;
+
+ if (!uj)
+ vty_out(vty,
+ "RpAddress HoldTime Priority\n");
+
+ while (frag_rp_cnt--) {
+ pim_addr rp_addr;
+
+ bsm_rpinfo = (struct bsmmsg_rpinfo *)buf;
+ /* unaligned, again */
+ memcpy(&rp_addr, &bsm_rpinfo->rpaddr,
+ sizeof(rp_addr));
+
+ buf += sizeof(struct bsmmsg_rpinfo);
+ offset += sizeof(struct bsmmsg_rpinfo);
+
+ if (uj) {
+ json_row = json_object_new_object();
+ json_object_string_addf(
+ json_row, "Rp Address", "%pPA",
+ &rp_addr);
+ json_object_int_add(
+ json_row, "Rp HoldTime",
+ ntohs(bsm_rpinfo->rp_holdtime));
+ json_object_int_add(json_row,
+ "Rp Priority",
+ bsm_rpinfo->rp_pri);
+ json_object_object_addf(
+ json_group, json_row, "%pPA",
+ &rp_addr);
+ } else {
+ vty_out(vty, "%-15pPA %-12d %d\n",
+ &rp_addr,
+ ntohs(bsm_rpinfo->rp_holdtime),
+ bsm_rpinfo->rp_pri);
+ }
+ }
+ vty_out(vty, "\n");
+ }
+
+ fragment++;
+ }
+
+ if (uj)
+ vty_json(vty, json);
+}
+
+int pim_show_bsm_db_helper(const char *vrf, struct vty *vty, bool uj)
+{
+ struct pim_instance *pim;
+ struct vrf *v;
+
+ v = vrf_lookup_by_name(vrf ? vrf : VRF_DEFAULT_NAME);
+
+ if (!v)
+ return CMD_WARNING;
+
+ pim = v->info;
+
+ if (!pim) {
+ vty_out(vty, "%% Unable to find pim instance\n");
+ return CMD_WARNING;
+ }
+
+ pim_show_bsm_db(v->info, vty, uj);
+
+ return CMD_SUCCESS;
+}
diff --git a/pimd/pim_cmd_common.h b/pimd/pim_cmd_common.h
index 27c029670..d34a4af9e 100644
--- a/pimd/pim_cmd_common.h
+++ b/pimd/pim_cmd_common.h
@@ -62,6 +62,10 @@ int pim_process_ip_mroute_cmd(struct vty *vty, const char *interface,
const char *group_str, const char *source_str);
int pim_process_no_ip_mroute_cmd(struct vty *vty, const char *interface,
const char *group_str, const char *src_str);
+int pim_process_bsm_cmd(struct vty *vty);
+int pim_process_no_bsm_cmd(struct vty *vty);
+int pim_process_unicast_bsm_cmd(struct vty *vty);
+int pim_process_no_unicast_bsm_cmd(struct vty *vty);
void json_object_pim_upstream_add(json_object *json, struct pim_upstream *up);
void pim_show_rpf(struct pim_instance *pim, struct vty *vty, json_object *json);
void pim_show_neighbors_secondary(struct pim_instance *pim, struct vty *vty);
@@ -114,6 +118,9 @@ void pim_show_neighbors_single(struct pim_instance *pim, struct vty *vty,
const char *neighbor, json_object *json);
void pim_show_neighbors(struct pim_instance *pim, struct vty *vty,
json_object *json);
+int pim_show_group_rp_mappings_info_helper(const char *vrf, struct vty *vty,
+ bool uj);
+int pim_show_bsm_db_helper(const char *vrf, struct vty *vty, bool uj);
int gm_process_query_max_response_time_cmd(struct vty *vty,
const char *qmrt_str);
int gm_process_no_query_max_response_time_cmd(struct vty *vty);
@@ -186,6 +193,8 @@ void pim_show_interface_traffic(struct pim_instance *pim, struct vty *vty,
int pim_show_interface_traffic_helper(const char *vrf, const char *if_name,
struct vty *vty, bool uj);
void clear_pim_interfaces(struct pim_instance *pim);
+void pim_show_bsr(struct pim_instance *pim, struct vty *vty, bool uj);
+int pim_show_bsr_helper(const char *vrf, struct vty *vty, bool uj);
/*
* Special Macro to allow us to get the correct pim_instance;
*/
diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c
index 6f272f008..db9156b04 100644
--- a/pimd/pim_iface.c
+++ b/pimd/pim_iface.c
@@ -689,7 +689,7 @@ static void pim_if_addr_del_pim(struct connected *ifc)
{
struct pim_interface *pim_ifp = ifc->ifp->info;
- if (ifc->address->family != AF_INET) {
+ if (ifc->address->family != PIM_AF) {
/* non-IPv4 address */
return;
}
@@ -843,7 +843,7 @@ void pim_if_addr_del_all(struct interface *ifp)
for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
struct prefix *p = ifc->address;
- if (p->family != AF_INET)
+ if (p->family != PIM_AF)
continue;
pim_if_addr_del(ifc, 1 /* force_prim_as_any=true */);
diff --git a/pimd/pim_igmp_mtrace.c b/pimd/pim_igmp_mtrace.c
index f6c23c8e8..259c34c81 100644
--- a/pimd/pim_igmp_mtrace.c
+++ b/pimd/pim_igmp_mtrace.c
@@ -365,19 +365,9 @@ static int mtrace_un_forward_packet(struct pim_instance *pim, struct ip *ip_hdr,
if (ip_hdr->ip_ttl-- <= 1)
return -1;
- ip_hdr->ip_sum = in_cksum(ip_hdr, ip_hdr->ip_hl * 4);
-
- fd = pim_socket_raw(IPPROTO_RAW);
-
- if (fd < 0)
- return -1;
-
- pim_socket_ip_hdr(fd);
-
if (interface == NULL) {
memset(&nexthop, 0, sizeof(nexthop));
if (!pim_nexthop_lookup(pim, &nexthop, ip_hdr->ip_dst, 0)) {
- close(fd);
if (PIM_DEBUG_MTRACE)
zlog_debug(
"Dropping mtrace packet, no route to destination");
@@ -389,6 +379,15 @@ static int mtrace_un_forward_packet(struct pim_instance *pim, struct ip *ip_hdr,
if_out = interface;
}
+ ip_hdr->ip_sum = in_cksum(ip_hdr, ip_hdr->ip_hl * 4);
+
+ fd = pim_socket_raw(IPPROTO_RAW);
+
+ if (fd < 0)
+ return -1;
+
+ pim_socket_ip_hdr(fd);
+
ret = pim_socket_bind(fd, if_out);
if (ret < 0) {
@@ -770,7 +769,8 @@ int igmp_mtrace_recv_qry_req(struct gm_sock *igmp, struct ip *ip_hdr,
}
/* 6.2.2 8. If this router is the Rendez-vous Point */
- if (pim_rp_i_am_rp(pim, mtracep->grp_addr)) {
+ if (mtracep->grp_addr.s_addr != INADDR_ANY &&
+ pim_rp_i_am_rp(pim, mtracep->grp_addr)) {
mtrace_rsp_set_fwd_code(rspp, MTRACE_FWD_CODE_REACHED_RP);
/* 7.7.1. PIM-SM ...RP has not performed source-specific join */
if (rspp->src_mask == MTRACE_SRC_MASK_GROUP)
diff --git a/pimd/pim_memory.c b/pimd/pim_memory.c
index 1d811d900..1780b60a6 100644
--- a/pimd/pim_memory.c
+++ b/pimd/pim_memory.c
@@ -37,7 +37,6 @@ DEFINE_MTYPE(PIMD, PIM_IFCHANNEL, "PIM interface (S,G) state");
DEFINE_MTYPE(PIMD, PIM_UPSTREAM, "PIM upstream (S,G) state");
DEFINE_MTYPE(PIMD, PIM_SSMPINGD, "PIM sspimgd socket");
DEFINE_MTYPE(PIMD, PIM_STATIC_ROUTE, "PIM Static Route");
-DEFINE_MTYPE(PIMD, PIM_BR, "PIM Bridge Router info");
DEFINE_MTYPE(PIMD, PIM_RP, "PIM RP info");
DEFINE_MTYPE(PIMD, PIM_FILTER_NAME, "PIM RP filter info");
DEFINE_MTYPE(PIMD, PIM_MSDP_PEER, "PIM MSDP peer");
diff --git a/pimd/pim_memory.h b/pimd/pim_memory.h
index 4e5fcde7d..385c81052 100644
--- a/pimd/pim_memory.h
+++ b/pimd/pim_memory.h
@@ -36,7 +36,6 @@ DECLARE_MTYPE(PIM_IFCHANNEL);
DECLARE_MTYPE(PIM_UPSTREAM);
DECLARE_MTYPE(PIM_SSMPINGD);
DECLARE_MTYPE(PIM_STATIC_ROUTE);
-DECLARE_MTYPE(PIM_BR);
DECLARE_MTYPE(PIM_RP);
DECLARE_MTYPE(PIM_FILTER_NAME);
DECLARE_MTYPE(PIM_MSDP_PEER);
diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c
index 220706945..f1fd2ef73 100644
--- a/pimd/pim_mroute.c
+++ b/pimd/pim_mroute.c
@@ -634,7 +634,7 @@ static int process_igmp_packet(struct pim_instance *pim, const char *buf,
connected_src = pim_if_connected_to_source(ifp, ip_hdr->ip_src);
- if (!connected_src) {
+ if (!connected_src && !pim_addr_is_any(ip_hdr->ip_src)) {
if (PIM_DEBUG_GM_PACKETS) {
zlog_debug(
"Recv IGMP packet on interface: %s from a non-connected source: %pI4",
@@ -644,7 +644,8 @@ static int process_igmp_packet(struct pim_instance *pim, const char *buf,
}
pim_ifp = ifp->info;
- ifaddr = connected_src->u.prefix4;
+ ifaddr = connected_src ? connected_src->u.prefix4
+ : pim_ifp->primary_address;
igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->gm_socket_list, ifaddr);
if (PIM_DEBUG_GM_PACKETS) {
@@ -655,11 +656,11 @@ static int process_igmp_packet(struct pim_instance *pim, const char *buf,
}
if (igmp)
pim_igmp_packet(igmp, (char *)buf, buf_size);
- else if (PIM_DEBUG_GM_PACKETS) {
+ else if (PIM_DEBUG_GM_PACKETS)
zlog_debug(
- "No IGMP socket on interface: %s with connected source: %pFX",
- ifp->name, connected_src);
- }
+ "No IGMP socket on interface: %s with connected source: %pI4",
+ ifp->name, &ifaddr);
+
return 0;
}
#endif
diff --git a/pimd/pim_mroute.h b/pimd/pim_mroute.h
index d6798c52a..c409b9ed0 100644
--- a/pimd/pim_mroute.h
+++ b/pimd/pim_mroute.h
@@ -39,10 +39,8 @@
#if defined(HAVE_LINUX_MROUTE_H)
#include <linux/mroute.h>
#else
-#ifndef VTYSH_EXTRACT_PL
#include "linux/mroute.h"
#endif
-#endif
typedef struct vifctl pim_vifctl;
typedef struct igmpmsg kernmsg;
@@ -86,10 +84,8 @@ typedef struct sioc_sg_req pim_sioc_sg_req;
#if defined(HAVE_LINUX_MROUTE6_H)
#include <linux/mroute6.h>
#else
-#ifndef VTYSH_EXTRACT_PL
#include "linux/mroute6.h"
#endif
-#endif
#ifndef MRT_INIT
#define MRT_BASE MRT6_BASE
diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c
index 12f8ffedf..c4ff912cd 100644
--- a/pimd/pim_nb_config.c
+++ b/pimd/pim_nb_config.c
@@ -24,6 +24,7 @@
#include "lib/northbound_cli.h"
#include "pim_igmpv3.h"
#include "pim_neighbor.h"
+#include "pim_nht.h"
#include "pim_pim.h"
#include "pim_mlag.h"
#include "pim_bfd.h"
@@ -146,6 +147,7 @@ static int pim_cmd_interface_add(struct interface *ifp)
pim_ifp->pim_enable = true;
pim_if_addr_add_all(ifp);
+ pim_upstream_nh_if_update(pim_ifp->pim, ifp);
pim_if_membership_refresh(ifp);
pim_if_create_pimreg(pim_ifp->pim);
@@ -171,6 +173,7 @@ static int pim_cmd_interface_delete(struct interface *ifp)
if (!pim_ifp->gm_enable) {
pim_if_addr_del_all(ifp);
+ pim_upstream_nh_if_update(pim_ifp->pim, ifp);
pim_if_delete(ifp);
}
diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c
index 9feb064e9..a33da6456 100644
--- a/pimd/pim_nht.c
+++ b/pimd/pim_nht.c
@@ -469,6 +469,40 @@ static int pim_update_upstream_nh(struct pim_instance *pim,
return 0;
}
+static int pim_upstream_nh_if_update_helper(struct hash_bucket *bucket,
+ void *arg)
+{
+ struct pim_nexthop_cache *pnc = bucket->data;
+ struct pnc_hash_walk_data *pwd = arg;
+ struct pim_instance *pim = pwd->pim;
+ struct interface *ifp = pwd->ifp;
+ struct nexthop *nh_node = NULL;
+ ifindex_t first_ifindex;
+
+ for (nh_node = pnc->nexthop; nh_node; nh_node = nh_node->next) {
+ first_ifindex = nh_node->ifindex;
+ if (ifp != if_lookup_by_index(first_ifindex, pim->vrf->vrf_id))
+ continue;
+
+ if (pnc->upstream_hash->count) {
+ pim_update_upstream_nh(pim, pnc);
+ break;
+ }
+ }
+
+ return HASHWALK_CONTINUE;
+}
+
+void pim_upstream_nh_if_update(struct pim_instance *pim, struct interface *ifp)
+{
+ struct pnc_hash_walk_data pwd;
+
+ pwd.pim = pim;
+ pwd.ifp = ifp;
+
+ hash_walk(pim->rpf_hash, pim_upstream_nh_if_update_helper, &pwd);
+}
+
uint32_t pim_compute_ecmp_hash(struct prefix *src, struct prefix *grp)
{
uint32_t hash_val;
@@ -495,12 +529,14 @@ static int pim_ecmp_nexthop_search(struct pim_instance *pim,
uint32_t hash_val = 0, mod_val = 0;
uint8_t nh_iter = 0, found = 0;
uint32_t i, num_nbrs = 0;
- pim_addr nh_addr = nexthop->mrib_nexthop_addr;
- pim_addr grp_addr = pim_addr_from_prefix(grp);
+ struct pim_interface *pim_ifp;
if (!pnc || !pnc->nexthop_num || !nexthop)
return 0;
+ pim_addr nh_addr = nexthop->mrib_nexthop_addr;
+ pim_addr grp_addr = pim_addr_from_prefix(grp);
+
memset(&nbrs, 0, sizeof(nbrs));
memset(&ifps, 0, sizeof(ifps));
@@ -610,10 +646,13 @@ static int pim_ecmp_nexthop_search(struct pim_instance *pim,
nh_iter++;
continue;
}
- if (!ifp->info) {
+
+ pim_ifp = ifp->info;
+
+ if (!pim_ifp || !pim_ifp->pim_enable) {
if (PIM_DEBUG_PIM_NHT)
zlog_debug(
- "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %pPA)",
+ "%s: pim not enabled on input interface %s(%s) (ifindex=%d, RPF for source %pPA)",
__func__, ifp->name, pim->vrf->name,
first_ifindex, &src);
if (nh_iter == mod_val)
@@ -881,6 +920,7 @@ int pim_ecmp_nexthop_lookup(struct pim_instance *pim,
uint8_t i = 0;
uint32_t hash_val = 0, mod_val = 0;
uint32_t num_nbrs = 0;
+ struct pim_interface *pim_ifp;
if (PIM_DEBUG_PIM_NHT_DETAIL)
zlog_debug("%s: Looking up: %pPA(%s), last lookup time: %lld",
@@ -963,10 +1003,12 @@ int pim_ecmp_nexthop_lookup(struct pim_instance *pim,
continue;
}
- if (!ifp->info) {
+ pim_ifp = ifp->info;
+
+ if (!pim_ifp || !pim_ifp->pim_enable) {
if (PIM_DEBUG_PIM_NHT)
zlog_debug(
- "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %pPA)",
+ "%s: pim not enabled on input interface %s(%s) (ifindex=%d, RPF for source %pPA)",
__func__, ifp->name, pim->vrf->name,
first_ifindex, &src);
if (i == mod_val)
diff --git a/pimd/pim_nht.h b/pimd/pim_nht.h
index 240e61d98..f487a21ba 100644
--- a/pimd/pim_nht.h
+++ b/pimd/pim_nht.h
@@ -53,6 +53,11 @@ struct pim_nexthop_cache {
uint32_t bsr_count;
};
+struct pnc_hash_walk_data {
+ struct pim_instance *pim;
+ struct interface *ifp;
+};
+
int pim_parse_nexthop_update(ZAPI_CALLBACK_ARGS);
int pim_find_or_track_nexthop(struct pim_instance *pim, pim_addr addr,
struct pim_upstream *up, struct rp_info *rp,
@@ -77,5 +82,5 @@ void pim_nht_bsr_del(struct pim_instance *pim, pim_addr bsr_addr);
/* RPF(bsr_addr) == src_ip%src_ifp? */
bool pim_nht_bsr_rpf_check(struct pim_instance *pim, pim_addr bsr_addr,
struct interface *src_ifp, pim_addr src_ip);
-
+void pim_upstream_nh_if_update(struct pim_instance *pim, struct interface *ifp);
#endif
diff --git a/pimd/pim_register.c b/pimd/pim_register.c
index 4e2c44b17..a37759e0d 100644
--- a/pimd/pim_register.c
+++ b/pimd/pim_register.c
@@ -36,7 +36,6 @@
#include "pim_rp.h"
#include "pim_register.h"
#include "pim_upstream.h"
-#include "pim_br.h"
#include "pim_rpf.h"
#include "pim_oil.h"
#include "pim_zebra.h"
@@ -642,24 +641,13 @@ int pim_register_recv(struct interface *ifp, pim_addr dest_addr,
}
if (*bits & PIM_REGISTER_BORDER_BIT) {
- pim_addr pimbr = pim_br_get_pmbr(&sg);
if (PIM_DEBUG_PIM_PACKETS)
zlog_debug(
- "%s: Received Register message with Border bit set",
+ "%s: Received Register message with Border bit set, ignoring",
__func__);
- if (pim_addr_is_any(pimbr))
- pim_br_set_pmbr(&sg, src_addr);
- else if (pim_addr_cmp(src_addr, pimbr)) {
- pim_register_stop_send(ifp, &sg, dest_addr,
- src_addr);
- if (PIM_DEBUG_PIM_PACKETS)
- zlog_debug(
- "%s: Sending register-Stop to %s and dropping mr. packet",
- __func__, "Sender");
/* Drop Packet Silently */
- return 0;
- }
+ return 0;
}
struct pim_upstream *upstream = pim_upstream_find(pim, &sg);
diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c
index 1dce6b356..c3e6a303f 100644
--- a/pimd/pim_rp.c
+++ b/pimd/pim_rp.c
@@ -950,10 +950,12 @@ void pim_rp_setup(struct pim_instance *pim)
pim_find_or_track_nexthop(pim, nht_p, NULL, rp_info, NULL);
if (!pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop,
- nht_p, &rp_info->group, 1))
+ nht_p, &rp_info->group, 1)) {
if (PIM_DEBUG_PIM_NHT_RP)
zlog_debug(
"Unable to lookup nexthop for rp specified");
+ pim_rp_nexthop_del(rp_info);
+ }
}
}
diff --git a/pimd/pim_rpf.c b/pimd/pim_rpf.c
index a28278c58..d237a7312 100644
--- a/pimd/pim_rpf.c
+++ b/pimd/pim_rpf.c
@@ -61,6 +61,7 @@ bool pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop,
ifindex_t first_ifindex = 0;
int found = 0;
int i = 0;
+ struct pim_interface *pim_ifp;
#if PIM_IPV == 4
/*
@@ -97,9 +98,10 @@ bool pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop,
zclient_lookup_nexthop(pim, nexthop_tab, router->multipath,
addr, PIM_NEXTHOP_LOOKUP_MAX);
if (num_ifindex < 1) {
- zlog_warn(
- "%s %s: could not find nexthop ifindex for address %pPAs",
- __FILE__, __func__, &addr);
+ if (PIM_DEBUG_PIM_NHT)
+ zlog_debug(
+ "%s %s: could not find nexthop ifindex for address %pPAs",
+ __FILE__, __func__, &addr);
return false;
}
@@ -117,15 +119,16 @@ bool pim_nexthop_lookup(struct pim_instance *pim, struct pim_nexthop *nexthop,
continue;
}
- if (!ifp->info) {
+ pim_ifp = ifp->info;
+ if (!pim_ifp || !pim_ifp->pim_enable) {
if (PIM_DEBUG_ZEBRA)
zlog_debug(
- "%s: multicast not enabled on input interface %s (ifindex=%d, RPF for source %pPAs)",
+ "%s: pim not enabled on input interface %s (ifindex=%d, RPF for source %pPAs)",
__func__, ifp->name, first_ifindex,
&addr);
i++;
- } else if (neighbor_needed
- && !pim_if_connected_to_source(ifp, addr)) {
+ } else if (neighbor_needed &&
+ !pim_if_connected_to_source(ifp, addr)) {
nbr = pim_neighbor_find(ifp,
nexthop_tab[i].nexthop_addr);
if (PIM_DEBUG_PIM_TRACE_DETAIL)
diff --git a/pimd/pim_tib.c b/pimd/pim_tib.c
index 8f5de3e93..3455e3006 100644
--- a/pimd/pim_tib.c
+++ b/pimd/pim_tib.c
@@ -49,7 +49,8 @@ tib_sg_oil_setup(struct pim_instance *pim, pim_sgaddr sg, struct interface *oif)
if (up) {
memcpy(&nexthop, &up->rpf.source_nexthop,
sizeof(struct pim_nexthop));
- pim_ecmp_nexthop_lookup(pim, &nexthop, vif_source, &grp, 0);
+ (void)pim_ecmp_nexthop_lookup(pim, &nexthop, vif_source, &grp,
+ 0);
if (nexthop.interface)
input_iface_vif_index = pim_if_find_vifindex_by_ifindex(
pim, nexthop.interface->ifindex);
diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c
index 0742daa4d..6b58fbb5c 100644
--- a/pimd/pim_upstream.c
+++ b/pimd/pim_upstream.c
@@ -46,7 +46,6 @@
#include "pim_oil.h"
#include "pim_macro.h"
#include "pim_rp.h"
-#include "pim_br.h"
#include "pim_register.h"
#include "pim_msdp.h"
#include "pim_jp_agg.h"
@@ -1422,8 +1421,8 @@ struct pim_upstream *pim_upstream_keep_alive_timer_proc(
}
if (I_am_RP(pim, up->sg.grp)) {
- pim_br_clear_pmbr(&up->sg);
/*
+ * Handle Border Router
* We need to do more here :)
* But this is the start.
*/
diff --git a/pimd/pim_util.c b/pimd/pim_util.c
index 4b67dbf1b..150e1a01e 100644
--- a/pimd/pim_util.c
+++ b/pimd/pim_util.c
@@ -166,3 +166,15 @@ int pim_get_all_mcast_group(struct prefix *prefix)
#endif
return 1;
}
+
+bool pim_addr_is_multicast(pim_addr addr)
+{
+#if PIM_IPV == 4
+ if (IN_MULTICAST(addr.s_addr))
+ return true;
+#else
+ if (IN6_IS_ADDR_MULTICAST(&addr))
+ return true;
+#endif
+ return false;
+}
diff --git a/pimd/pim_util.h b/pimd/pim_util.h
index a4362bef9..6af79ddf6 100644
--- a/pimd/pim_util.h
+++ b/pimd/pim_util.h
@@ -37,4 +37,5 @@ int pim_is_group_224_0_0_0_24(struct in_addr group_addr);
int pim_is_group_224_4(struct in_addr group_addr);
bool pim_is_group_filtered(struct pim_interface *pim_ifp, pim_addr *grp);
int pim_get_all_mcast_group(struct prefix *prefix);
+bool pim_addr_is_multicast(pim_addr addr);
#endif /* PIM_UTIL_H */
diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c
index 9021f1e12..553c1314d 100644
--- a/pimd/pim_vty.c
+++ b/pimd/pim_vty.c
@@ -401,7 +401,7 @@ static int gm_config_write(struct vty *vty, int writes,
vty_out(vty, " ipv6 mld last-member-query-interval %d\n",
pim_ifp->gm_specific_query_max_response_time_dsec);
- return 0;
+ return writes;
}
#endif
diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c
index 87cf43413..0481c3a76 100644
--- a/pimd/pim_zlookup.c
+++ b/pimd/pim_zlookup.c
@@ -279,7 +279,7 @@ static int zclient_read_nexthop(struct pim_instance *pim,
* secondary
*/
struct interface *ifp = if_lookup_by_index(
- nexthop_tab[num_ifindex].ifindex,
+ nh_ifi,
nexthop_vrf_id);
if (!ifp)
diff --git a/pimd/subdir.am b/pimd/subdir.am
index aa06b8647..fd7255cb8 100644
--- a/pimd/subdir.am
+++ b/pimd/subdir.am
@@ -6,11 +6,6 @@ if PIMD
sbin_PROGRAMS += pimd/pimd
bin_PROGRAMS += pimd/mtracebis
noinst_PROGRAMS += pimd/test_igmpv3_join
-vtysh_scan += \
- pimd/pim_cmd.c \
- pimd/pim6_cmd.c \
- pimd/pim6_mld.c \
- #end
vtysh_daemons += pimd
vtysh_daemons += pim6d
man8 += $(MANBUILD)/frr-pimd.8
@@ -21,7 +16,6 @@ pim_common = \
pimd/pim_addr.c \
pimd/pim_assert.c \
pimd/pim_bfd.c \
- pimd/pim_br.c \
pimd/pim_bsm.c \
pimd/pim_cmd_common.c \
pimd/pim_errors.c \
@@ -103,7 +97,6 @@ noinst_HEADERS += \
pimd/pim_addr.h \
pimd/pim_assert.h \
pimd/pim_bfd.h \
- pimd/pim_br.h \
pimd/pim_bsm.h \
pimd/pim_cmd.h \
pimd/pim_cmd_common.h \
diff --git a/python/callgraph-dot.py b/python/callgraph-dot.py
index f80766a08..7d9825bd1 100644
--- a/python/callgraph-dot.py
+++ b/python/callgraph-dot.py
@@ -321,15 +321,31 @@ extra_info = {
"lsp_processq_complete",
],
# zebra - main WQ
- ("mq_add_handler", "work_queue_add"): ["meta_queue_process",],
- ("meta_queue_process", "work_queue_add"): ["meta_queue_process",],
+ ("mq_add_handler", "work_queue_add"): [
+ "meta_queue_process",
+ ],
+ ("meta_queue_process", "work_queue_add"): [
+ "meta_queue_process",
+ ],
# bgpd - label pool WQ
- ("bgp_lp_get", "work_queue_add"): ["lp_cbq_docallback",],
- ("bgp_lp_event_chunk", "work_queue_add"): ["lp_cbq_docallback",],
- ("bgp_lp_event_zebra_up", "work_queue_add"): ["lp_cbq_docallback",],
+ ("bgp_lp_get", "work_queue_add"): [
+ "lp_cbq_docallback",
+ ],
+ ("bgp_lp_event_chunk", "work_queue_add"): [
+ "lp_cbq_docallback",
+ ],
+ ("bgp_lp_event_zebra_up", "work_queue_add"): [
+ "lp_cbq_docallback",
+ ],
# bgpd - main WQ
- ("bgp_process", "work_queue_add"): ["bgp_process_wq", "bgp_processq_del",],
- ("bgp_add_eoiu_mark", "work_queue_add"): ["bgp_process_wq", "bgp_processq_del",],
+ ("bgp_process", "work_queue_add"): [
+ "bgp_process_wq",
+ "bgp_processq_del",
+ ],
+ ("bgp_add_eoiu_mark", "work_queue_add"): [
+ "bgp_process_wq",
+ "bgp_processq_del",
+ ],
# clear node WQ
("bgp_clear_route_table", "work_queue_add"): [
"bgp_clear_route_node",
@@ -337,7 +353,9 @@ extra_info = {
"bgp_clear_node_complete",
],
# rfapi WQs
- ("rfapi_close", "work_queue_add"): ["rfapi_deferred_close_workfunc",],
+ ("rfapi_close", "work_queue_add"): [
+ "rfapi_deferred_close_workfunc",
+ ],
("rfapiRibUpdatePendingNode", "work_queue_add"): [
"rfapiRibDoQueuedCallback",
"rfapiRibQueueItemDelete",
diff --git a/python/clippy/__init__.py b/python/clippy/__init__.py
index 344a1c91e..7c73598e5 100644
--- a/python/clippy/__init__.py
+++ b/python/clippy/__init__.py
@@ -17,11 +17,29 @@
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
import os, stat
+
+try:
+ from enum import IntFlag as _IntFlag
+except ImportError:
+ # python <3.6
+ from enum import IntEnum as _IntFlag # type: ignore
+
import _clippy
-from _clippy import parse, Graph, GraphNode
+from _clippy import (
+ parse,
+ Graph,
+ GraphNode,
+ CMD_ATTR_YANG,
+ CMD_ATTR_HIDDEN,
+ CMD_ATTR_DEPRECATED,
+ CMD_ATTR_NOSH,
+)
+
+frr_top_src = os.path.dirname(
+ os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+)
-frr_top_src = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
def graph_iterate(graph):
"""iterator yielding all nodes of a graph
@@ -78,3 +96,10 @@ def wrdiff(filename, buf, reffiles=[]):
with open(newname, "w") as out:
out.write(buf)
os.rename(newname, filename)
+
+
+class CmdAttr(_IntFlag):
+ YANG = CMD_ATTR_YANG
+ HIDDEN = CMD_ATTR_HIDDEN
+ DEPRECATED = CMD_ATTR_DEPRECATED
+ NOSH = CMD_ATTR_NOSH
diff --git a/python/clippy/elf.py b/python/clippy/elf.py
index 02cb2e38b..d4d1f4cb8 100644
--- a/python/clippy/elf.py
+++ b/python/clippy/elf.py
@@ -16,7 +16,7 @@
# 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
-'''
+"""
Wrapping layer and additional utility around _clippy.ELFFile.
Essentially, the C bits have the low-level ELF access bits that should be
@@ -28,7 +28,7 @@ across architecture, word size and even endianness boundaries. Both the C
module (through GElf_*) and this code (cf. struct.unpack format mangling
in ELFDissectStruct) will take appropriate measures to flip and resize
fields as needed.
-'''
+"""
import struct
from collections import OrderedDict
@@ -40,16 +40,18 @@ from _clippy import ELFFile, ELFAccessError
# data access
#
+
class ELFNull(object):
- '''
+ """
NULL pointer, returned instead of ELFData
- '''
+ """
+
def __init__(self):
self.symname = None
self._dstsect = None
def __repr__(self):
- return '<ptr: NULL>'
+ return "<ptr: NULL>"
def __hash__(self):
return hash(None)
@@ -57,33 +59,37 @@ class ELFNull(object):
def get_string(self):
return None
+
class ELFUnresolved(object):
- '''
+ """
Reference to an unresolved external symbol, returned instead of ELFData
:param symname: name of the referenced symbol
:param addend: offset added to the symbol, normally zero
- '''
+ """
+
def __init__(self, symname, addend):
self.addend = addend
self.symname = symname
self._dstsect = None
def __repr__(self):
- return '<unresolved: %s+%d>' % (self.symname, self.addend)
+ return "<unresolved: %s+%d>" % (self.symname, self.addend)
def __hash__(self):
return hash((self.symname, self.addend))
+
class ELFData(object):
- '''
+ """
Actual data somewhere in the ELF file.
:type dstsect: ELFSubset
:param dstsect: container data area (section or entire file)
:param dstoffs: byte offset into dstsect
:param dstlen: byte size of object, or None if unknown, open-ended or string
- '''
+ """
+
def __init__(self, dstsect, dstoffs, dstlen):
self._dstsect = dstsect
self._dstoffs = dstoffs
@@ -91,62 +97,78 @@ class ELFData(object):
self.symname = None
def __repr__(self):
- return '<ptr: %s+0x%05x/%d>' % (self._dstsect.name, self._dstoffs, self._dstlen or -1)
+ return "<ptr: %s+0x%05x/%d>" % (
+ self._dstsect.name,
+ self._dstoffs,
+ self._dstlen or -1,
+ )
def __hash__(self):
return hash((self._dstsect, self._dstoffs))
def get_string(self):
- '''
+ """
Interpret as C string / null terminated UTF-8 and get the actual text.
- '''
+ """
try:
- return self._dstsect[self._dstoffs:str].decode('UTF-8')
+ return self._dstsect[self._dstoffs : str].decode("UTF-8")
except:
- import pdb; pdb.set_trace()
+ import pdb
+
+ pdb.set_trace()
def get_data(self, reflen):
- '''
+ """
Interpret as some structure (and check vs. expected length)
:param reflen: expected size of the object, compared against actual
size (which is only known in rare cases, mostly when directly
accessing a symbol since symbols have their destination object
size recorded)
- '''
+ """
if self._dstlen is not None and self._dstlen != reflen:
- raise ValueError('symbol size mismatch (got %d, expected %d)' % (self._dstlen, reflen))
- return self._dstsect[self._dstoffs:self._dstoffs+reflen]
+ raise ValueError(
+ "symbol size mismatch (got %d, expected %d)" % (self._dstlen, reflen)
+ )
+ return self._dstsect[self._dstoffs : self._dstoffs + reflen]
def offset(self, offs, within_symbol=False):
- '''
+ """
Get another ELFData at an offset
:param offs: byte offset, can be negative (e.g. in container_of)
:param within_symbol: retain length information
- '''
+ """
if self._dstlen is None or not within_symbol:
return ELFData(self._dstsect, self._dstoffs + offs, None)
else:
return ELFData(self._dstsect, self._dstoffs + offs, self._dstlen - offs)
+
#
# dissection data items
#
+
class ELFDissectData(object):
- '''
+ """
Common bits for ELFDissectStruct and ELFDissectUnion
- '''
+ """
+
+ def __init__(self):
+ self._data = None
+ self.elfclass = None
def __len__(self):
- '''
+ """
Used for boolean evaluation, e.g. "if struct: ..."
- '''
- return not (isinstance(self._data, ELFNull) or isinstance(self._data, ELFUnresolved))
+ """
+ return not (
+ isinstance(self._data, ELFNull) or isinstance(self._data, ELFUnresolved)
+ )
def container_of(self, parent, fieldname):
- '''
+ """
Assume this struct is embedded in a larger struct and get at the larger
Python ``self.container_of(a, b)`` = C ``container_of(self, a, b)``
@@ -154,25 +176,26 @@ class ELFDissectData(object):
:param parent: class (not instance) of the larger struct
:param fieldname: fieldname that refers back to this
:returns: instance of parent, with fieldname set to this object
- '''
+ """
offset = 0
- if not hasattr(parent, '_efields'):
+ if not hasattr(parent, "_efields"):
parent._setup_efields()
for field in parent._efields[self.elfclass]:
if field[0] == fieldname:
break
spec = field[1]
- if spec == 'P':
- spec = 'I' if self.elfclass == 32 else 'Q'
+ if spec == "P":
+ spec = "I" if self.elfclass == 32 else "Q"
offset += struct.calcsize(spec)
else:
- raise AttributeError('%r not found in %r.fields' % (fieldname, parent))
+ raise AttributeError("%r not found in %r.fields" % (fieldname, parent))
+
+ return parent(self._data.offset(-offset), replace={fieldname: self})
- return parent(self._data.offset(-offset), replace = {fieldname: self})
class ELFDissectStruct(ELFDissectData):
- '''
+ """
Decode and provide access to a struct somewhere in the ELF file
Handles pointers and strings somewhat nicely. Create a subclass for each
@@ -205,30 +228,31 @@ class ELFDissectStruct(ELFDissectData):
.. attribute:: fieldrename
Dictionary to rename fields, useful if fields comes from tiabwarfo.py.
- '''
+ """
class Pointer(object):
- '''
+ """
Quick wrapper for pointers to further structs
This is just here to avoid going into infinite loops when loading
structs that have pointers to each other (e.g. struct xref <-->
struct xrefdata.) The pointer destination is only instantiated when
actually accessed.
- '''
+ """
+
def __init__(self, cls, ptr):
self.cls = cls
self.ptr = ptr
def __repr__(self):
- return '<Pointer:%s %r>' % (self.cls.__name__, self.ptr)
+ return "<Pointer:%s %r>" % (self.cls.__name__, self.ptr)
def __call__(self):
if isinstance(self.ptr, ELFNull):
return None
return self.cls(self.ptr)
- def __new__(cls, dataptr, parent = None, replace = None):
+ def __new__(cls, dataptr, parent=None, replace=None):
if dataptr._dstsect is None:
return super().__new__(cls)
@@ -239,19 +263,19 @@ class ELFDissectStruct(ELFDissectData):
dataptr._dstsect._pointers[(cls, dataptr)] = obj
return obj
- replacements = 'lLnN'
+ replacements = "lLnN"
@classmethod
def _preproc_structspec(cls, elfclass, spec):
elfbits = elfclass
- if hasattr(spec, 'calcsize'):
- spec = '%ds' % (spec.calcsize(elfclass),)
+ if hasattr(spec, "calcsize"):
+ spec = "%ds" % (spec.calcsize(elfclass),)
if elfbits == 32:
- repl = ['i', 'I']
+ repl = ["i", "I"]
else:
- repl = ['q', 'Q']
+ repl = ["q", "Q"]
for c in cls.replacements:
spec = spec.replace(c, repl[int(c.isupper())])
return spec
@@ -269,8 +293,8 @@ class ELFDissectStruct(ELFDissectData):
size += struct.calcsize(newf[1])
cls._esize[elfclass] = size
- def __init__(self, dataptr, parent = None, replace = None):
- if not hasattr(self.__class__, '_efields'):
+ def __init__(self, dataptr, parent=None, replace=None):
+ if not hasattr(self.__class__, "_efields"):
self._setup_efields()
self._fdata = None
@@ -290,12 +314,12 @@ class ELFDissectStruct(ELFDissectData):
# need to correlate output from struct.unpack with extra metadata
# about the particular fields, so note down byte offsets (in locs)
# and tuple indices of pointers (in ptrs)
- pspec = ''
+ pspec = ""
locs = {}
ptrs = set()
for idx, spec in enumerate(pspecl):
- if spec == 'P':
+ if spec == "P":
ptrs.add(idx)
spec = self._elfsect.ptrtype
@@ -326,7 +350,9 @@ class ELFDissectStruct(ELFDissectData):
self._fdata[name] = replace[name]
continue
- if isinstance(self.fields[i][1], type) and issubclass(self.fields[i][1], ELFDissectData):
+ if isinstance(self.fields[i][1], type) and issubclass(
+ self.fields[i][1], ELFDissectData
+ ):
dataobj = self.fields[i][1](dataptr.offset(locs[i]), self)
self._fdata[name] = dataobj
continue
@@ -353,35 +379,41 @@ class ELFDissectStruct(ELFDissectData):
def __repr__(self):
if not isinstance(self._data, ELFData):
- return '<%s: %r>' % (self.__class__.__name__, self._data)
- return '<%s: %s>' % (self.__class__.__name__,
- ', '.join(['%s=%r' % t for t in self._fdata.items()]))
+ return "<%s: %r>" % (self.__class__.__name__, self._data)
+ return "<%s: %s>" % (
+ self.__class__.__name__,
+ ", ".join(["%s=%r" % t for t in self._fdata.items()]),
+ )
@classmethod
def calcsize(cls, elfclass):
- '''
+ """
Sum up byte size of this struct
Wraps struct.calcsize with some extra features.
- '''
- if not hasattr(cls, '_efields'):
+ """
+ if not hasattr(cls, "_efields"):
cls._setup_efields()
- pspec = ''.join([f[1] for f in cls._efields[elfclass]])
+ pspec = "".join([f[1] for f in cls._efields[elfclass]])
- ptrtype = 'I' if elfclass == 32 else 'Q'
- pspec = pspec.replace('P', ptrtype)
+ ptrtype = "I" if elfclass == 32 else "Q"
+ pspec = pspec.replace("P", ptrtype)
return struct.calcsize(pspec)
+
class ELFDissectUnion(ELFDissectData):
- '''
+ """
Decode multiple structs in the same place.
Not currently used (and hence not tested.) Worked at some point but not
needed anymore and may be borked now. Remove this comment when using.
- '''
- def __init__(self, dataptr, parent = None):
+ """
+
+ members = {}
+
+ def __init__(self, dataptr, parent=None):
self._dataptr = dataptr
self._parent = parent
self.members = []
@@ -391,31 +423,44 @@ class ELFDissectUnion(ELFDissectData):
setattr(self, name, item)
def __repr__(self):
- return '<%s: %s>' % (self.__class__.__name__, ', '.join([repr(i) for i in self.members]))
+ return "<%s: %s>" % (
+ self.__class__.__name__,
+ ", ".join([repr(i) for i in self.members]),
+ )
@classmethod
def calcsize(cls, elfclass):
return max([member.calcsize(elfclass) for name, member in cls.members])
+
#
# wrappers for spans of ELF data
#
+
class ELFSubset(object):
- '''
+ """
Common abstract base for section-level and file-level access.
- '''
+ """
def __init__(self):
super().__init__()
+ self.name = None
+ self._obj = None
+ self._elffile = None
+ self.ptrtype = None
+ self.endian = None
self._pointers = WeakValueDictionary()
+ def _wrap_data(self, data, dstsect):
+ raise NotImplementedError()
+
def __hash__(self):
return hash(self.name)
def __getitem__(self, k):
- '''
+ """
Read data from slice
Subscript **must** be a slice; a simple index will not return a byte
@@ -425,22 +470,22 @@ class ELFSubset(object):
- `this[123:456]` - extract specific range
- `this[123:str]` - extract until null byte. The slice stop value is
the `str` type (or, technically, `unicode`.)
- '''
+ """
return self._obj[k]
def getreloc(self, offset):
- '''
+ """
Check for a relocation record at the specified offset.
- '''
+ """
return self._obj.getreloc(offset)
- def iter_data(self, scls, slice_ = slice(None)):
- '''
+ def iter_data(self, scls, slice_=slice(None)):
+ """
Assume an array of structs present at a particular slice and decode
:param scls: ELFDissectData subclass for the struct
:param slice_: optional range specification
- '''
+ """
size = scls.calcsize(self._elffile.elfclass)
offset = slice_.start or 0
@@ -453,7 +498,7 @@ class ELFSubset(object):
offset += size
def pointer(self, offset):
- '''
+ """
Try to dereference a pointer value
This checks whether there's a relocation at the given offset and
@@ -463,10 +508,12 @@ class ELFSubset(object):
:param offset: byte offset from beginning of section,
or virtual address in file
:returns: ELFData wrapping pointed-to object
- '''
+ """
ptrsize = struct.calcsize(self.ptrtype)
- data = struct.unpack(self.endian + self.ptrtype, self[offset:offset + ptrsize])[0]
+ data = struct.unpack(
+ self.endian + self.ptrtype, self[offset : offset + ptrsize]
+ )[0]
reloc = self.getreloc(offset)
dstsect = None
@@ -497,14 +544,15 @@ class ELFSubset(object):
# wrap_data is different between file & section
return self._wrap_data(data, dstsect)
+
class ELFDissectSection(ELFSubset):
- '''
+ """
Access the contents of an ELF section like ``.text`` or ``.data``
:param elfwrap: ELFDissectFile wrapper for the file
:param idx: section index in section header table
:param section: section object from C module
- '''
+ """
def __init__(self, elfwrap, idx, section):
super().__init__()
@@ -524,8 +572,9 @@ class ELFDissectSection(ELFSubset):
dstsect = self._elfwrap.get_section(dstsect.idx)
return ELFData(dstsect, offs, None)
+
class ELFDissectFile(ELFSubset):
- '''
+ """
Access the contents of an ELF file.
Note that offsets for array subscript and relocation/pointer access are
@@ -537,7 +586,7 @@ class ELFDissectFile(ELFSubset):
address like 0x400000 on x86.
:param filename: ELF file to open
- '''
+ """
def __init__(self, filename):
super().__init__()
@@ -546,8 +595,8 @@ class ELFDissectFile(ELFSubset):
self._elffile = self._obj = ELFFile(filename)
self._sections = {}
- self.ptrtype = 'I' if self._elffile.elfclass == 32 else 'Q'
- self.endian = '>' if self._elffile.bigendian else '<'
+ self.ptrtype = "I" if self._elffile.elfclass == 32 else "Q"
+ self.endian = ">" if self._elffile.bigendian else "<"
@property
def _elfwrap(self):
@@ -557,9 +606,9 @@ class ELFDissectFile(ELFSubset):
return ELFData(self, data, None)
def get_section(self, secname):
- '''
+ """
Look up section by name or index
- '''
+ """
if isinstance(secname, int):
sh_idx = secname
section = self._elffile.get_section_idx(secname)
diff --git a/python/clippy/uidhash.py b/python/clippy/uidhash.py
index bf994d389..0fd886221 100644
--- a/python/clippy/uidhash.py
+++ b/python/clippy/uidhash.py
@@ -19,13 +19,14 @@
import struct
from hashlib import sha256
-def bititer(data, bits, startbit = True):
- '''
+
+def bititer(data, bits, startbit=True):
+ """
just iterate the individual bits out from a bytes object
if startbit is True, an '1' bit is inserted at the very beginning
goes <bits> at a time, starts at LSB.
- '''
+ """
bitavail, v = 0, 0
if startbit and len(data) > 0:
v = data.pop(0)
@@ -41,31 +42,33 @@ def bititer(data, bits, startbit = True):
bitavail -= bits
v >>= bits
+
def base32c(data):
- '''
+ """
Crockford base32 with extra dashes
- '''
+ """
chs = "0123456789ABCDEFGHJKMNPQRSTVWXYZ"
- o = ''
+ o = ""
if type(data) == str:
data = [ord(v) for v in data]
else:
data = list(data)
for i, bits in enumerate(bititer(data, 5)):
if i == 5:
- o = o + '-'
+ o = o + "-"
elif i == 10:
break
o = o + chs[bits]
return o
+
def uidhash(filename, hashstr, hashu32a, hashu32b):
- '''
+ """
xref Unique ID hash used in FRRouting
- '''
- filename = '/'.join(filename.rsplit('/')[-2:])
+ """
+ filename = "/".join(filename.rsplit("/")[-2:])
- hdata = filename.encode('UTF-8') + hashstr.encode('UTF-8')
- hdata += struct.pack('>II', hashu32a, hashu32b)
+ hdata = filename.encode("UTF-8") + hashstr.encode("UTF-8")
+ hdata += struct.pack(">II", hashu32a, hashu32b)
i = sha256(hdata).digest()
return base32c(i)
diff --git a/python/makefile.py b/python/makefile.py
index afc993b5b..573871fb6 100644
--- a/python/makefile.py
+++ b/python/makefile.py
@@ -160,6 +160,17 @@ for clippy_file in clippy_scan:
# combine daemon .xref files into frr.xref
out_lines.append("")
+xref_targets = [
+ target
+ for target in xref_targets
+ if target
+ not in [
+ "bgpd/rfp-example/rfptest/rfptest",
+ "pimd/mtracebis",
+ "tools/ssd",
+ "vtysh/vtysh",
+ ]
+]
out_lines.append(
"xrefs = %s" % (" ".join(["%s.xref" % target for target in xref_targets]))
)
diff --git a/python/runtests.py b/python/runtests.py
index bcf650b32..70deaa35d 100644
--- a/python/runtests.py
+++ b/python/runtests.py
@@ -5,9 +5,11 @@ import os
try:
import _clippy
except ImportError:
- sys.stderr.write('''these tests need to be run with the _clippy C extension
+ sys.stderr.write(
+ """these tests need to be run with the _clippy C extension
module available. Try running "clippy runtests.py ...".
-''')
+"""
+ )
sys.exit(1)
os.chdir(os.path.dirname(os.path.abspath(__file__)))
diff --git a/python/test_xrelfo.py b/python/test_xrelfo.py
index 3ae24ea7b..3379959dc 100644
--- a/python/test_xrelfo.py
+++ b/python/test_xrelfo.py
@@ -22,20 +22,21 @@ import pytest
from pprint import pprint
root = os.path.dirname(os.path.dirname(__file__))
-sys.path.append(os.path.join(root, 'python'))
+sys.path.append(os.path.join(root, "python"))
import xrelfo
from clippy import elf, uidhash
+
def test_uidhash():
- assert uidhash.uidhash("lib/test_xref.c", "logging call", 3, 0) \
- == 'H7KJB-67TBH'
+ assert uidhash.uidhash("lib/test_xref.c", "logging call", 3, 0) == "H7KJB-67TBH"
+
def test_xrelfo_other():
for data in [
- elf.ELFNull(),
- elf.ELFUnresolved('somesym', 0),
- ]:
+ elf.ELFNull(),
+ elf.ELFUnresolved("somesym", 0),
+ ]:
dissect = xrelfo.XrefPtr(data)
print(repr(dissect))
@@ -43,9 +44,10 @@ def test_xrelfo_other():
with pytest.raises(AttributeError):
dissect.xref
+
def test_xrelfo_obj():
xrelfo_ = xrelfo.Xrelfo()
- edf = xrelfo_.load_elf(os.path.join(root, 'lib/.libs/zclient.o'), 'zclient.lo')
+ edf = xrelfo_.load_elf(os.path.join(root, "lib/.libs/zclient.o"), "zclient.lo")
xrefs = xrelfo_._xrefs
with pytest.raises(elf.ELFAccessError):
@@ -54,12 +56,13 @@ def test_xrelfo_obj():
pprint(xrefs[0])
pprint(xrefs[0]._data)
+
def test_xrelfo_bin():
xrelfo_ = xrelfo.Xrelfo()
- edf = xrelfo_.load_elf(os.path.join(root, 'lib/.libs/libfrr.so'), 'libfrr.la')
+ edf = xrelfo_.load_elf(os.path.join(root, "lib/.libs/libfrr.so"), "libfrr.la")
xrefs = xrelfo_._xrefs
- assert edf[0:4] == b'\x7fELF'
+ assert edf[0:4] == b"\x7fELF"
pprint(xrefs[0])
pprint(xrefs[0]._data)
diff --git a/python/tiabwarfo.py b/python/tiabwarfo.py
index 4a6cd6ad7..b19c75673 100644
--- a/python/tiabwarfo.py
+++ b/python/tiabwarfo.py
@@ -23,10 +23,19 @@ import re
import argparse
import json
-structs = ['xref', 'xref_logmsg', 'xref_threadsched', 'xref_install_element', 'xrefdata', 'xrefdata_logmsg', 'cmd_element']
-
-def extract(filename='lib/.libs/libfrr.so'):
- '''
+structs = [
+ "xref",
+ "xref_logmsg",
+ "xref_threadsched",
+ "xref_install_element",
+ "xrefdata",
+ "xrefdata_logmsg",
+ "cmd_element",
+]
+
+
+def extract(filename="lib/.libs/libfrr.so"):
+ """
Convert output from "pahole" to JSON.
Example pahole output:
@@ -41,26 +50,30 @@ def extract(filename='lib/.libs/libfrr.so'):
/* size: 32, cachelines: 1, members: 5 */
/* last cacheline: 32 bytes */
};
- '''
- pahole = subprocess.check_output(['pahole', '-C', ','.join(structs), filename]).decode('UTF-8')
+ """
+ pahole = subprocess.check_output(
+ ["pahole", "-C", ",".join(structs), filename]
+ ).decode("UTF-8")
- struct_re = re.compile(r'^struct ([^ ]+) \{([^\}]+)};', flags=re.M | re.S)
- field_re = re.compile(r'^\s*(?P<type>[^;\(]+)\s+(?P<name>[^;\[\]]+)(?:\[(?P<array>\d+)\])?;\s*\/\*(?P<comment>.*)\*\/\s*$')
- comment_re = re.compile(r'^\s*\/\*.*\*\/\s*$')
+ struct_re = re.compile(r"^struct ([^ ]+) \{([^\}]+)};", flags=re.M | re.S)
+ field_re = re.compile(
+ r"^\s*(?P<type>[^;\(]+)\s+(?P<name>[^;\[\]]+)(?:\[(?P<array>\d+)\])?;\s*\/\*(?P<comment>.*)\*\/\s*$"
+ )
+ comment_re = re.compile(r"^\s*\/\*.*\*\/\s*$")
pastructs = struct_re.findall(pahole)
out = {}
for sname, data in pastructs:
this = out.setdefault(sname, {})
- fields = this.setdefault('fields', [])
+ fields = this.setdefault("fields", [])
lines = data.strip().splitlines()
next_offs = 0
for line in lines:
- if line.strip() == '':
+ if line.strip() == "":
continue
m = comment_re.match(line)
if m is not None:
@@ -68,51 +81,55 @@ def extract(filename='lib/.libs/libfrr.so'):
m = field_re.match(line)
if m is not None:
- offs, size = m.group('comment').strip().split()
+ offs, size = m.group("comment").strip().split()
offs = int(offs)
size = int(size)
- typ_ = m.group('type').strip()
- name = m.group('name')
+ typ_ = m.group("type").strip()
+ name = m.group("name")
- if name.startswith('(*'):
+ if name.startswith("(*"):
# function pointer
- typ_ = typ_ + ' *'
- name = name[2:].split(')')[0]
+ typ_ = typ_ + " *"
+ name = name[2:].split(")")[0]
data = {
- 'name': name,
- 'type': typ_,
- # 'offset': offs,
- # 'size': size,
+ "name": name,
+ "type": typ_,
+ # 'offset': offs,
+ # 'size': size,
}
- if m.group('array'):
- data['array'] = int(m.group('array'))
+ if m.group("array"):
+ data["array"] = int(m.group("array"))
fields.append(data)
if offs != next_offs:
- raise ValueError('%d padding bytes before struct %s.%s' % (offs - next_offs, sname, name))
+ raise ValueError(
+ "%d padding bytes before struct %s.%s"
+ % (offs - next_offs, sname, name)
+ )
next_offs = offs + size
continue
- raise ValueError('cannot process line: %s' % line)
+ raise ValueError("cannot process line: %s" % line)
return out
+
class FieldApplicator(object):
- '''
+ """
Fill ELFDissectStruct fields list from pahole/JSON
Uses the JSON file created by the above code to fill in the struct fields
in subclasses of ELFDissectStruct.
- '''
+ """
# only what we really need. add more as needed.
packtypes = {
- 'int': 'i',
- 'uint8_t': 'B',
- 'uint16_t': 'H',
- 'uint32_t': 'I',
- 'char': 's',
+ "int": "i",
+ "uint8_t": "B",
+ "uint16_t": "H",
+ "uint32_t": "I",
+ "char": "s",
}
def __init__(self, data):
@@ -126,60 +143,65 @@ class FieldApplicator(object):
def resolve(self, cls):
out = []
- #offset = 0
+ # offset = 0
+
+ fieldrename = getattr(cls, "fieldrename", {})
- fieldrename = getattr(cls, 'fieldrename', {})
def mkname(n):
return (fieldrename.get(n, n),)
- for field in self.data[cls.struct]['fields']:
- typs = field['type'].split()
- typs = [i for i in typs if i not in ['const']]
+ for field in self.data[cls.struct]["fields"]:
+ typs = field["type"].split()
+ typs = [i for i in typs if i not in ["const"]]
# this will break reuse of xrefstructs.json across 32bit & 64bit
# platforms
- #if field['offset'] != offset:
+ # if field['offset'] != offset:
# assert offset < field['offset']
# out.append(('_pad', '%ds' % (field['offset'] - offset,)))
# pretty hacky C types handling, but covers what we need
ptrlevel = 0
- while typs[-1] == '*':
+ while typs[-1] == "*":
typs.pop(-1)
ptrlevel += 1
if ptrlevel > 0:
- packtype = ('P', None)
+ packtype = ("P", None)
if ptrlevel == 1:
- if typs[0] == 'char':
- packtype = ('P', str)
- elif typs[0] == 'struct' and typs[1] in self.clsmap:
- packtype = ('P', self.clsmap[typs[1]])
- elif typs[0] == 'enum':
- packtype = ('I',)
+ if typs[0] == "char":
+ packtype = ("P", str)
+ elif typs[0] == "struct" and typs[1] in self.clsmap:
+ packtype = ("P", self.clsmap[typs[1]])
+ elif typs[0] == "enum":
+ packtype = ("I",)
elif typs[0] in self.packtypes:
packtype = (self.packtypes[typs[0]],)
- elif typs[0] == 'struct':
+ elif typs[0] == "struct":
if typs[1] in self.clsmap:
packtype = (self.clsmap[typs[1]],)
else:
- raise ValueError('embedded struct %s not in extracted data' % (typs[1],))
+ raise ValueError(
+ "embedded struct %s not in extracted data" % (typs[1],)
+ )
else:
- raise ValueError('cannot decode field %s in struct %s (%s)' % (
- cls.struct, field['name'], field['type']))
-
- if 'array' in field and typs[0] == 'char':
- packtype = ('%ds' % field['array'],)
- out.append(mkname(field['name']) + packtype)
- elif 'array' in field:
- for i in range(0, field['array']):
- out.append(mkname('%s_%d' % (field['name'], i)) + packtype)
+ raise ValueError(
+ "cannot decode field %s in struct %s (%s)"
+ % (cls.struct, field["name"], field["type"])
+ )
+
+ if "array" in field and typs[0] == "char":
+ packtype = ("%ds" % field["array"],)
+ out.append(mkname(field["name"]) + packtype)
+ elif "array" in field:
+ for i in range(0, field["array"]):
+ out.append(mkname("%s_%d" % (field["name"], i)) + packtype)
else:
- out.append(mkname(field['name']) + packtype)
+ out.append(mkname(field["name"]) + packtype)
- #offset = field['offset'] + field['size']
+ # offset = field['offset'] + field['size']
cls.fields = out
@@ -187,16 +209,30 @@ class FieldApplicator(object):
for cls in self.classes:
self.resolve(cls)
+
def main():
- argp = argparse.ArgumentParser(description = 'FRR DWARF structure extractor')
- argp.add_argument('-o', dest='output', type=str, help='write JSON output', default='python/xrefstructs.json')
- argp.add_argument('-i', dest='input', type=str, help='ELF file to read', default='lib/.libs/libfrr.so')
+ argp = argparse.ArgumentParser(description="FRR DWARF structure extractor")
+ argp.add_argument(
+ "-o",
+ dest="output",
+ type=str,
+ help="write JSON output",
+ default="python/xrefstructs.json",
+ )
+ argp.add_argument(
+ "-i",
+ dest="input",
+ type=str,
+ help="ELF file to read",
+ default="lib/.libs/libfrr.so",
+ )
args = argp.parse_args()
out = extract(args.input)
- with open(args.output + '.tmp', 'w') as fd:
+ with open(args.output + ".tmp", "w") as fd:
json.dump(out, fd, indent=2, sort_keys=True)
- os.rename(args.output + '.tmp', args.output)
+ os.rename(args.output + ".tmp", args.output)
+
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/python/vtysh-cmd-check.py b/python/vtysh-cmd-check.py
deleted file mode 100644
index ef9eea41a..000000000
--- a/python/vtysh-cmd-check.py
+++ /dev/null
@@ -1,72 +0,0 @@
-#!/usr/bin/env python3
-#
-# Quick demo program that checks whether files define commands that aren't
-# in vtysh. Execute after building.
-#
-# This is free and unencumbered software released into the public domain.
-#
-# Anyone is free to copy, modify, publish, use, compile, sell, or
-# distribute this software, either in source code form or as a compiled
-# binary, for any purpose, commercial or non-commercial, and by any
-# means.
-#
-# In jurisdictions that recognize copyright laws, the author or authors
-# of this software dedicate any and all copyright interest in the
-# software to the public domain. We make this dedication for the benefit
-# of the public at large and to the detriment of our heirs and
-# successors. We intend this dedication to be an overt act of
-# relinquishment in perpetuity of all present and future rights to this
-# software under copyright law.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
-# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-# OTHER DEALINGS IN THE SOFTWARE.
-#
-# For more information, please refer to <http://unlicense.org/>
-
-import os
-import json
-import subprocess
-
-os.chdir(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
-
-with open("frr.xref", "r") as fd:
- data = json.load(fd)
-
-vtysh_scan, _ = subprocess.Popen(
- ["make", "var-vtysh_scan"], stdout=subprocess.PIPE
-).communicate()
-vtysh_scan = set(vtysh_scan.decode("US-ASCII").split())
-
-check = set()
-vtysh = {}
-
-for cmd, defs in data["cli"].items():
- for binary, clidef in defs.items():
- if clidef["defun"]["file"].startswith("vtysh/"):
- vtysh[clidef["string"]] = clidef
-
-for cmd, defs in data["cli"].items():
- for binary, clidef in defs.items():
- if clidef["defun"]["file"].startswith("vtysh/"):
- continue
-
- if clidef["defun"]["file"] not in vtysh_scan:
- vtysh_def = vtysh.get(clidef["string"])
- if vtysh_def is not None:
- print(
- "\033[33m%s defines %s, has a custom define in vtysh %s\033[m"
- % (clidef["defun"]["file"], cmd, vtysh_def["defun"]["file"])
- )
- else:
- print(
- "\033[31m%s defines %s, not in vtysh_scan\033[m"
- % (clidef["defun"]["file"], cmd)
- )
- check.add(clidef["defun"]["file"])
-
-print("\nfiles to check:\n\t" + " ".join(sorted(check)))
diff --git a/python/xref2vtysh.py b/python/xref2vtysh.py
new file mode 100644
index 000000000..f18aa20c9
--- /dev/null
+++ b/python/xref2vtysh.py
@@ -0,0 +1,389 @@
+# FRR xref vtysh command extraction
+#
+# Copyright (C) 2022 David Lamparter for NetDEF, Inc.
+#
+# 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
+
+"""
+Generate vtysh_cmd.c from frr .xref file(s).
+
+This can run either standalone or as part of xrelfo. The latter saves a
+non-negligible amount of time (0.5s on average systems, more on e.g. slow ARMs)
+since serializing and deserializing JSON is a significant bottleneck in this.
+"""
+
+import sys
+import os
+import re
+import pathlib
+import argparse
+from collections import defaultdict
+import difflib
+
+import json
+
+try:
+ import ujson as json # type: ignore
+except ImportError:
+ pass
+
+frr_top_src = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+
+# vtysh needs to know which daemon(s) to send commands to. For lib/, this is
+# not quite obvious...
+
+daemon_flags = {
+ "lib/agentx.c": "VTYSH_ISISD|VTYSH_RIPD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA",
+ "lib/filter.c": "VTYSH_ACL",
+ "lib/filter_cli.c": "VTYSH_ACL",
+ "lib/if.c": "VTYSH_INTERFACE",
+ "lib/keychain.c": "VTYSH_RIPD|VTYSH_EIGRPD|VTYSH_OSPF6D",
+ "lib/lib_vty.c": "VTYSH_ALL",
+ "lib/log_vty.c": "VTYSH_ALL",
+ "lib/nexthop_group.c": "VTYSH_NH_GROUP",
+ "lib/resolver.c": "VTYSH_NHRPD|VTYSH_BGPD",
+ "lib/routemap.c": "VTYSH_RMAP",
+ "lib/routemap_cli.c": "VTYSH_RMAP",
+ "lib/spf_backoff.c": "VTYSH_ISISD",
+ "lib/thread.c": "VTYSH_ALL",
+ "lib/vrf.c": "VTYSH_VRF",
+ "lib/vty.c": "VTYSH_ALL",
+}
+
+vtysh_cmd_head = """/* autogenerated file, DO NOT EDIT! */
+#include <zebra.h>
+
+#include "command.h"
+#include "linklist.h"
+
+#include "vtysh/vtysh.h"
+"""
+
+if sys.stderr.isatty():
+ _fmt_red = "\033[31m"
+ _fmt_green = "\033[32m"
+ _fmt_clear = "\033[m"
+else:
+ _fmt_red = _fmt_green = _fmt_clear = ""
+
+
+def c_escape(text: str) -> str:
+ """
+ Escape string for output into C source code.
+
+ Handles only what's needed here. CLI strings and help text don't contain
+ weird special characters.
+ """
+ return text.replace("\\", "\\\\").replace('"', '\\"').replace("\n", "\\n")
+
+
+class NodeDict(defaultdict):
+ """
+ CLI node ID (integer) -> dict of commands in that node.
+ """
+
+ nodenames = {} # Dict[int, str]
+
+ def __init__(self):
+ super().__init__(dict)
+
+ def items_named(self):
+ for k, v in self.items():
+ yield self.nodename(k), v
+
+ @classmethod
+ def nodename(cls, nodeid: int) -> str:
+ return cls.nodenames.get(nodeid, str(nodeid))
+
+ @classmethod
+ def load_nodenames(cls):
+ with open(os.path.join(frr_top_src, "lib", "command.h"), "r") as fd:
+ command_h = fd.read()
+
+ nodes = re.search(r"enum\s+node_type\s+\{(.*?)\}", command_h, re.S)
+ if nodes is None:
+ raise RuntimeError(
+ "regex failed to match on lib/command.h (to get CLI node names)"
+ )
+
+ text = nodes.group(1)
+ text = re.sub(r"/\*.*?\*/", "", text, flags=re.S)
+ text = re.sub(r"//.*?$", "", text, flags=re.M)
+ text = text.replace(",", " ")
+ text = text.split()
+
+ for i, name in enumerate(text):
+ cls.nodenames[i] = name
+
+
+class CommandEntry:
+ """
+ CLI command definition.
+
+ - one DEFUN creates at most one of these, even if the same command is
+ installed in multiple CLI nodes (e.g. BGP address-family nodes)
+ - for each CLI node, commands with the same CLI string are merged. This
+ is *almost* irrelevant - ospfd & ospf6d define some identical commands
+ in the route-map node. Those must be merged for things to work
+ correctly.
+ """
+
+ all_defs = [] # List[CommandEntry]
+ warn_counter = 0
+
+ def __init__(self, origin, name, spec):
+ self.origin = origin
+ self.name = name
+ self._spec = spec
+ self._registered = False
+
+ self.cmd = spec["string"]
+ self._cmd_normalized = self.normalize_cmd(self.cmd)
+
+ self.hidden = "hidden" in spec.get("attrs", [])
+ self.daemons = self._get_daemons()
+
+ self.doclines = self._spec["doc"].splitlines(keepends=True)
+ if not self.doclines[-1].endswith("\n"):
+ self.warn_loc("docstring does not end with \\n")
+
+ def warn_loc(self, wtext, nodename=None):
+ """
+ Print warning with parseable (compiler style) location
+
+ Matching the way compilers emit file/lineno means editors/IDE can
+ identify / jump to the error location.
+ """
+
+ if nodename:
+ prefix = ": [%s] %s:" % (nodename, self.name)
+ else:
+ prefix = ": %s:" % (self.name,)
+
+ for line in wtext.rstrip("\n").split("\n"):
+ sys.stderr.write(
+ "%s:%d%s %s\n"
+ % (
+ self._spec["defun"]["file"],
+ self._spec["defun"]["line"],
+ prefix,
+ line,
+ )
+ )
+ prefix = "- "
+
+ CommandEntry.warn_counter += 1
+
+ def _get_daemons(self):
+ path = pathlib.Path(self.origin)
+ if path.name == "vtysh":
+ return {}
+
+ defun_file = os.path.relpath(self._spec["defun"]["file"], frr_top_src)
+ defun_path = pathlib.Path(defun_file)
+
+ if defun_path.parts[0] != "lib":
+ if "." not in path.name:
+ # daemons don't have dots in their filename
+ return {"VTYSH_" + path.name.upper()}
+
+ # loadable modules - use directory name to determine daemon
+ return {"VTYSH_" + path.parts[-2].upper()}
+
+ if defun_file in daemon_flags:
+ return {daemon_flags[defun_file]}
+
+ v6_cmd = "ipv6" in self.name
+ if defun_file == "lib/plist.c":
+ if v6_cmd:
+ return {
+ "VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_PIM6D|VTYSH_BABELD|VTYSH_ISISD|VTYSH_FABRICD"
+ }
+ else:
+ return {
+ "VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_PIMD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_ISISD|VTYSH_FABRICD"
+ }
+
+ if defun_file == "lib/if_rmap.c":
+ if v6_cmd:
+ return {"VTYSH_RIPNGD"}
+ else:
+ return {"VTYSH_RIPD"}
+
+ return {}
+
+ def __repr__(self):
+ return "<CommandEntry %s: %r>" % (self.name, self.cmd)
+
+ def register(self):
+ """Track DEFUNs so each is only output once."""
+ if not self._registered:
+ self.all_defs.append(self)
+ self._registered = True
+ return self
+
+ def merge(self, other, nodename):
+ if self._cmd_normalized != other._cmd_normalized:
+ self.warn_loc(
+ "command definition mismatch, first definied as:\n%r" % (self.cmd,),
+ nodename=nodename,
+ )
+ other.warn_loc("later defined as:\n%r" % (other.cmd,), nodename=nodename)
+
+ if self._spec["doc"] != other._spec["doc"]:
+ self.warn_loc(
+ "help string mismatch, first defined here (-)", nodename=nodename
+ )
+ other.warn_loc(
+ "later defined here (+)\nnote: both commands define %r in same node (%s)"
+ % (self.cmd, nodename),
+ nodename=nodename,
+ )
+
+ d = difflib.Differ()
+ for diffline in d.compare(self.doclines, other.doclines):
+ if diffline.startswith(" "):
+ continue
+ if diffline.startswith("+ "):
+ diffline = _fmt_green + diffline
+ elif diffline.startswith("- "):
+ diffline = _fmt_red + diffline
+ sys.stderr.write("\t" + diffline.rstrip("\n") + _fmt_clear + "\n")
+
+ if self.hidden != other.hidden:
+ self.warn_loc(
+ "hidden flag mismatch, first %r here" % (self.hidden,),
+ nodename=nodename,
+ )
+ other.warn_loc(
+ "later %r here (+)\nnote: both commands define %r in same node (%s)"
+ % (other.hidden, self.cmd, nodename),
+ nodename=nodename,
+ )
+
+ # ensure name is deterministic regardless of input DEFUN order
+ self.name = min([self.name, other.name], key=lambda i: (len(i), i))
+ self.daemons.update(other.daemons)
+
+ def get_def(self):
+ doc = "\n".join(['\t"%s"' % c_escape(line) for line in self.doclines])
+ defsh = "DEFSH_HIDDEN" if self.hidden else "DEFSH"
+
+ # make daemon list deterministic
+ daemons = set()
+ for daemon in self.daemons:
+ daemons.update(daemon.split("|"))
+ daemon_str = "|".join(sorted(daemons))
+
+ return """
+%s (%s, %s_vtysh,
+\t"%s",
+%s)
+""" % (
+ defsh,
+ daemon_str,
+ self.name,
+ c_escape(self.cmd),
+ doc,
+ )
+
+ # accept slightly different command definitions that result in the same command
+ re_collapse_ws = re.compile(r"\s+")
+ re_remove_varnames = re.compile(r"\$[a-z][a-z0-9_]*")
+
+ @classmethod
+ def normalize_cmd(cls, cmd):
+ cmd = cmd.strip()
+ cmd = cls.re_collapse_ws.sub(" ", cmd)
+ cmd = cls.re_remove_varnames.sub("", cmd)
+ return cmd
+
+ @classmethod
+ def process(cls, nodes, name, origin, spec):
+ if "nosh" in spec.get("attrs", []):
+ return
+ if origin == "vtysh/vtysh":
+ return
+
+ if origin == "isisd/fabricd":
+ # dirty workaround :(
+ name = "fabricd_" + name
+
+ entry = cls(origin, name, spec)
+ if not entry.daemons:
+ return
+
+ for nodedata in spec.get("nodes", []):
+ node = nodes[nodedata["node"]]
+ if entry._cmd_normalized not in node:
+ node[entry._cmd_normalized] = entry.register()
+ else:
+ node[entry._cmd_normalized].merge(
+ entry, nodes.nodename(nodedata["node"])
+ )
+
+ @classmethod
+ def load(cls, xref):
+ nodes = NodeDict()
+
+ for cmd_name, origins in xref.get("cli", {}).items():
+ for origin, spec in origins.items():
+ CommandEntry.process(nodes, cmd_name, origin, spec)
+ return nodes
+
+ @classmethod
+ def output_defs(cls, ofd):
+ for entry in sorted(cls.all_defs, key=lambda i: i.name):
+ ofd.write(entry.get_def())
+
+ @classmethod
+ def output_install(cls, ofd, nodes):
+ ofd.write("\nvoid vtysh_init_cmd(void)\n{\n")
+
+ for name, items in sorted(nodes.items_named()):
+ for item in sorted(items.values(), key=lambda i: i.name):
+ ofd.write("\tinstall_element(%s, &%s_vtysh);\n" % (name, item.name))
+
+ ofd.write("}\n")
+
+ @classmethod
+ def run(cls, xref, ofd):
+ ofd.write(vtysh_cmd_head)
+
+ NodeDict.load_nodenames()
+ nodes = cls.load(xref)
+ cls.output_defs(ofd)
+ cls.output_install(ofd, nodes)
+
+
+def main():
+ argp = argparse.ArgumentParser(description="FRR xref to vtysh defs")
+ argp.add_argument(
+ "xreffile", metavar="XREFFILE", type=str, help=".xref file to read"
+ )
+ argp.add_argument("-Werror", action="store_const", const=True)
+ args = argp.parse_args()
+
+ with open(args.xreffile, "r") as fd:
+ data = json.load(fd)
+
+ CommandEntry.run(data, sys.stdout)
+
+ if args.Werror and CommandEntry.warn_counter:
+ sys.exit(1)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/python/xrelfo.py b/python/xrelfo.py
index 17262da8d..c75b4cb95 100644
--- a/python/xrelfo.py
+++ b/python/xrelfo.py
@@ -21,22 +21,34 @@ import os
import struct
import re
import traceback
-import json
+
+json_dump_args = {}
+
+try:
+ import ujson as json
+
+ json_dump_args["escape_forward_slashes"] = False
+except ImportError:
+ import json
+
import argparse
from clippy.uidhash import uidhash
from clippy.elf import *
-from clippy import frr_top_src
+from clippy import frr_top_src, CmdAttr
from tiabwarfo import FieldApplicator
+from xref2vtysh import CommandEntry
try:
- with open(os.path.join(frr_top_src, 'python', 'xrefstructs.json'), 'r') as fd:
+ with open(os.path.join(frr_top_src, "python", "xrefstructs.json"), "r") as fd:
xrefstructs = json.load(fd)
except FileNotFoundError:
- sys.stderr.write('''
+ sys.stderr.write(
+ """
The "xrefstructs.json" file (created by running tiabwarfo.py with the pahole
tool available) could not be found. It should be included with the sources.
-''')
+"""
+ )
sys.exit(1)
# constants, need to be kept in sync manually...
@@ -48,7 +60,7 @@ XREFT_INSTALL_ELEMENT = 0x301
# LOG_*
priovals = {}
-prios = ['0', '1', '2', 'E', 'W', 'N', 'I', 'D']
+prios = ["0", "1", "2", "E", "W", "N", "I", "D"]
class XrelfoJson(object):
@@ -61,9 +73,10 @@ class XrelfoJson(object):
def to_dict(self, refs):
pass
+
class Xref(ELFDissectStruct, XrelfoJson):
- struct = 'xref'
- fieldrename = {'type': 'typ'}
+ struct = "xref"
+ fieldrename = {"type": "typ"}
containers = {}
def __init__(self, *args, **kwargs):
@@ -76,7 +89,7 @@ class Xref(ELFDissectStruct, XrelfoJson):
def container(self):
if self._container is None:
if self.typ in self.containers:
- self._container = self.container_of(self.containers[self.typ], 'xref')
+ self._container = self.container_of(self.containers[self.typ], "xref")
return self._container
def check(self, *args, **kwargs):
@@ -85,10 +98,10 @@ class Xref(ELFDissectStruct, XrelfoJson):
class Xrefdata(ELFDissectStruct):
- struct = 'xrefdata'
+ struct = "xrefdata"
# uid is all zeroes in the data loaded from ELF
- fieldrename = {'uid': '_uid'}
+ fieldrename = {"uid": "_uid"}
def ref_from(self, xref, typ):
self.xref = xref
@@ -99,38 +112,84 @@ class Xrefdata(ELFDissectStruct):
return None
return uidhash(self.xref.file, self.hashstr, self.hashu32_0, self.hashu32_1)
+
class XrefPtr(ELFDissectStruct):
fields = [
- ('xref', 'P', Xref),
+ ("xref", "P", Xref),
]
+
class XrefThreadSched(ELFDissectStruct, XrelfoJson):
- struct = 'xref_threadsched'
+ struct = "xref_threadsched"
+
+
Xref.containers[XREFT_THREADSCHED] = XrefThreadSched
+
class XrefLogmsg(ELFDissectStruct, XrelfoJson):
- struct = 'xref_logmsg'
+ struct = "xref_logmsg"
def _warn_fmt(self, text):
- lines = text.split('\n')
- yield ((self.xref.file, self.xref.line), '%s:%d: %s (in %s())%s\n' % (self.xref.file, self.xref.line, lines[0], self.xref.func, ''.join(['\n' + l for l in lines[1:]])))
+ lines = text.split("\n")
+ yield (
+ (self.xref.file, self.xref.line),
+ "%s:%d: %s (in %s())%s\n"
+ % (
+ self.xref.file,
+ self.xref.line,
+ lines[0],
+ self.xref.func,
+ "".join(["\n" + l for l in lines[1:]]),
+ ),
+ )
fmt_regexes = [
- (re.compile(r'([\n\t]+)'), 'error: log message contains tab or newline'),
- # (re.compile(r'^(\s+)'), 'warning: log message starts with whitespace'),
- (re.compile(r'^((?:warn(?:ing)?|error):\s*)', re.I), 'warning: log message starts with severity'),
+ (re.compile(r"([\n\t]+)"), "error: log message contains tab or newline"),
+ # (re.compile(r'^(\s+)'), 'warning: log message starts with whitespace'),
+ (
+ re.compile(r"^((?:warn(?:ing)?|error):\s*)", re.I),
+ "warning: log message starts with severity",
+ ),
]
arg_regexes = [
- # the (?<![\?:] ) avoids warning for x ? inet_ntop(...) : "(bla)"
- (re.compile(r'((?<![\?:] )inet_ntop\s*\(\s*(?:[AP]F_INET|2)\s*,)'), 'cleanup: replace inet_ntop(AF_INET, ...) with %pI4', lambda s: True),
- (re.compile(r'((?<![\?:] )inet_ntop\s*\(\s*(?:[AP]F_INET6|10)\s*,)'), 'cleanup: replace inet_ntop(AF_INET6, ...) with %pI6', lambda s: True),
- (re.compile(r'((?<![\?:] )inet_ntoa)'), 'cleanup: replace inet_ntoa(...) with %pI4', lambda s: True),
- (re.compile(r'((?<![\?:] )ipaddr2str)'), 'cleanup: replace ipaddr2str(...) with %pIA', lambda s: True),
- (re.compile(r'((?<![\?:] )prefix2str)'), 'cleanup: replace prefix2str(...) with %pFX', lambda s: True),
- (re.compile(r'((?<![\?:] )prefix_mac2str)'), 'cleanup: replace prefix_mac2str(...) with %pEA', lambda s: True),
- (re.compile(r'((?<![\?:] )sockunion2str)'), 'cleanup: replace sockunion2str(...) with %pSU', lambda s: True),
-
- # (re.compile(r'^(\s*__(?:func|FUNCTION|PRETTY_FUNCTION)__\s*)'), 'error: debug message starts with __func__', lambda s: (s.priority & 7 == 7) ),
+ # the (?<![\?:] ) avoids warning for x ? inet_ntop(...) : "(bla)"
+ (
+ re.compile(r"((?<![\?:] )inet_ntop\s*\(\s*(?:[AP]F_INET|2)\s*,)"),
+ "cleanup: replace inet_ntop(AF_INET, ...) with %pI4",
+ lambda s: True,
+ ),
+ (
+ re.compile(r"((?<![\?:] )inet_ntop\s*\(\s*(?:[AP]F_INET6|10)\s*,)"),
+ "cleanup: replace inet_ntop(AF_INET6, ...) with %pI6",
+ lambda s: True,
+ ),
+ (
+ # string split-up here is to not trigger "inet_ntoa forbidden"
+ re.compile(r"((?<![\?:] )inet_" + r"ntoa)"),
+ "cleanup: replace inet_" + "ntoa(...) with %pI4",
+ lambda s: True,
+ ),
+ (
+ re.compile(r"((?<![\?:] )ipaddr2str)"),
+ "cleanup: replace ipaddr2str(...) with %pIA",
+ lambda s: True,
+ ),
+ (
+ re.compile(r"((?<![\?:] )prefix2str)"),
+ "cleanup: replace prefix2str(...) with %pFX",
+ lambda s: True,
+ ),
+ (
+ re.compile(r"((?<![\?:] )prefix_mac2str)"),
+ "cleanup: replace prefix_mac2str(...) with %pEA",
+ lambda s: True,
+ ),
+ (
+ re.compile(r"((?<![\?:] )sockunion2str)"),
+ "cleanup: replace sockunion2str(...) with %pSU",
+ lambda s: True,
+ ),
+ # (re.compile(r'^(\s*__(?:func|FUNCTION|PRETTY_FUNCTION)__\s*)'), 'error: debug message starts with __func__', lambda s: (s.priority & 7 == 7) ),
]
def check(self, wopt):
@@ -140,11 +199,11 @@ class XrefLogmsg(ELFDissectStruct, XrelfoJson):
out = []
for i, text in enumerate(items):
if (i % 2) == 1:
- out.append('\033[41;37;1m%s\033[m' % repr(text)[1:-1])
+ out.append("\033[41;37;1m%s\033[m" % repr(text)[1:-1])
else:
out.append(repr(text)[1:-1])
- excerpt = ''.join(out)
+ excerpt = "".join(out)
else:
excerpt = repr(itext)[1:-1]
return excerpt
@@ -165,68 +224,99 @@ class XrefLogmsg(ELFDissectStruct, XrelfoJson):
continue
excerpt = fmt_msg(rex, self.args)
- yield from self._warn_fmt('%s:\n\t"%s",\n\t%s' % (msg, repr(self.fmtstring)[1:-1], excerpt))
+ yield from self._warn_fmt(
+ '%s:\n\t"%s",\n\t%s' % (msg, repr(self.fmtstring)[1:-1], excerpt)
+ )
def dump(self):
- print('%-60s %s%s %-25s [EC %d] %s' % (
- '%s:%d %s()' % (self.xref.file, self.xref.line, self.xref.func),
- prios[self.priority & 7],
- priovals.get(self.priority & 0x30, ' '),
- self.xref.xrefdata.uid, self.ec, self.fmtstring))
+ print(
+ "%-60s %s%s %-25s [EC %d] %s"
+ % (
+ "%s:%d %s()" % (self.xref.file, self.xref.line, self.xref.func),
+ prios[self.priority & 7],
+ priovals.get(self.priority & 0x30, " "),
+ self.xref.xrefdata.uid,
+ self.ec,
+ self.fmtstring,
+ )
+ )
def to_dict(self, xrelfo):
- jsobj = dict([(i, getattr(self.xref, i)) for i in ['file', 'line', 'func']])
+ jsobj = dict([(i, getattr(self.xref, i)) for i in ["file", "line", "func"]])
if self.ec != 0:
- jsobj['ec'] = self.ec
- jsobj['fmtstring'] = self.fmtstring
- jsobj['args'] = self.args
- jsobj['priority'] = self.priority & 7
- jsobj['type'] = 'logmsg'
- jsobj['binary'] = self._elfsect._elfwrap.orig_filename
+ jsobj["ec"] = self.ec
+ jsobj["fmtstring"] = self.fmtstring
+ jsobj["args"] = self.args
+ jsobj["priority"] = self.priority & 7
+ jsobj["type"] = "logmsg"
+ jsobj["binary"] = self._elfsect._elfwrap.orig_filename
if self.priority & 0x10:
- jsobj.setdefault('flags', []).append('errno')
+ jsobj.setdefault("flags", []).append("errno")
if self.priority & 0x20:
- jsobj.setdefault('flags', []).append('getaddrinfo')
+ jsobj.setdefault("flags", []).append("getaddrinfo")
+
+ xrelfo["refs"].setdefault(self.xref.xrefdata.uid, []).append(jsobj)
- xrelfo['refs'].setdefault(self.xref.xrefdata.uid, []).append(jsobj)
Xref.containers[XREFT_LOGMSG] = XrefLogmsg
-class CmdElement(ELFDissectStruct, XrelfoJson):
- struct = 'cmd_element'
- cmd_attrs = { 0: None, 1: 'deprecated', 2: 'hidden'}
+class CmdElement(ELFDissectStruct, XrelfoJson):
+ struct = "cmd_element"
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
def to_dict(self, xrelfo):
- jsobj = xrelfo['cli'].setdefault(self.name, {}).setdefault(self._elfsect._elfwrap.orig_filename, {})
+ jsobj = (
+ xrelfo["cli"]
+ .setdefault(self.name, {})
+ .setdefault(self._elfsect._elfwrap.orig_filename, {})
+ )
+
+ jsobj.update(
+ {
+ "string": self.string,
+ "doc": self.doc,
+ }
+ )
+ if self.attr:
+ jsobj["attr"] = attr = self.attr
+ for attrname in CmdAttr.__members__:
+ val = CmdAttr[attrname]
+ if attr & val:
+ jsobj.setdefault("attrs", []).append(attrname.lower())
+ attr &= ~val
+
+ jsobj["defun"] = dict(
+ [(i, getattr(self.xref, i)) for i in ["file", "line", "func"]]
+ )
- jsobj.update({
- 'string': self.string,
- 'doc': self.doc,
- 'attr': self.cmd_attrs.get(self.attr, self.attr),
- })
- if jsobj['attr'] is None:
- del jsobj['attr']
-
- jsobj['defun'] = dict([(i, getattr(self.xref, i)) for i in ['file', 'line', 'func']])
Xref.containers[XREFT_DEFUN] = CmdElement
+
class XrefInstallElement(ELFDissectStruct, XrelfoJson):
- struct = 'xref_install_element'
+ struct = "xref_install_element"
def to_dict(self, xrelfo):
- jsobj = xrelfo['cli'].setdefault(self.cmd_element.name, {}).setdefault(self._elfsect._elfwrap.orig_filename, {})
- nodes = jsobj.setdefault('nodes', [])
+ jsobj = (
+ xrelfo["cli"]
+ .setdefault(self.cmd_element.name, {})
+ .setdefault(self._elfsect._elfwrap.orig_filename, {})
+ )
+ nodes = jsobj.setdefault("nodes", [])
+
+ nodes.append(
+ {
+ "node": self.node_type,
+ "install": dict(
+ [(i, getattr(self.xref, i)) for i in ["file", "line", "func"]]
+ ),
+ }
+ )
- nodes.append({
- 'node': self.node_type,
- 'install': dict([(i, getattr(self.xref, i)) for i in ['file', 'line', 'func']]),
- })
Xref.containers[XREFT_INSTALL_ELEMENT] = XrefInstallElement
@@ -243,86 +333,90 @@ fieldapply()
class Xrelfo(dict):
def __init__(self):
- super().__init__({
- 'refs': {},
- 'cli': {},
- })
+ super().__init__(
+ {
+ "refs": {},
+ "cli": {},
+ }
+ )
self._xrefs = []
def load_file(self, filename):
orig_filename = filename
- if filename.endswith('.la') or filename.endswith('.lo'):
- with open(filename, 'r') as fd:
+ if filename.endswith(".la") or filename.endswith(".lo"):
+ with open(filename, "r") as fd:
for line in fd:
line = line.strip()
- if line.startswith('#') or line == '' or '=' not in line:
+ if line.startswith("#") or line == "" or "=" not in line:
continue
- var, val = line.split('=', 1)
- if var not in ['library_names', 'pic_object']:
+ var, val = line.split("=", 1)
+ if var not in ["library_names", "pic_object"]:
continue
if val.startswith("'") or val.startswith('"'):
val = val[1:-1]
- if var == 'pic_object':
+ if var == "pic_object":
filename = os.path.join(os.path.dirname(filename), val)
break
val = val.strip().split()[0]
- filename = os.path.join(os.path.dirname(filename), '.libs', val)
+ filename = os.path.join(os.path.dirname(filename), ".libs", val)
break
else:
- raise ValueError('could not process libtool file "%s"' % orig_filename)
+ raise ValueError(
+ 'could not process libtool file "%s"' % orig_filename
+ )
while True:
- with open(filename, 'rb') as fd:
+ with open(filename, "rb") as fd:
hdr = fd.read(4)
- if hdr == b'\x7fELF':
+ if hdr == b"\x7fELF":
self.load_elf(filename, orig_filename)
return
- if hdr[:2] == b'#!':
+ if hdr[:2] == b"#!":
path, name = os.path.split(filename)
- filename = os.path.join(path, '.libs', name)
+ filename = os.path.join(path, ".libs", name)
continue
- if hdr[:1] == b'{':
- with open(filename, 'r') as fd:
+ if hdr[:1] == b"{":
+ with open(filename, "r") as fd:
self.load_json(fd)
return
- raise ValueError('cannot determine file type for %s' % (filename))
+ raise ValueError("cannot determine file type for %s" % (filename))
def load_elf(self, filename, orig_filename):
edf = ELFDissectFile(filename)
edf.orig_filename = orig_filename
- note = edf._elffile.find_note('FRRouting', 'XREF')
+ note = edf._elffile.find_note("FRRouting", "XREF")
if note is not None:
- endian = '>' if edf._elffile.bigendian else '<'
+ endian = ">" if edf._elffile.bigendian else "<"
mem = edf._elffile[note]
if edf._elffile.elfclass == 64:
- start, end = struct.unpack(endian + 'QQ', mem)
+ start, end = struct.unpack(endian + "QQ", mem)
start += note.start
end += note.start + 8
else:
- start, end = struct.unpack(endian + 'II', mem)
+ start, end = struct.unpack(endian + "II", mem)
start += note.start
end += note.start + 4
ptrs = edf.iter_data(XrefPtr, slice(start, end))
else:
- xrefarray = edf.get_section('xref_array')
+ xrefarray = edf.get_section("xref_array")
if xrefarray is None:
- raise ValueError('file has neither xref note nor xref_array section')
+ raise ValueError("file has neither xref note nor xref_array section")
ptrs = xrefarray.iter_data(XrefPtr)
for ptr in ptrs:
if ptr.xref is None:
- print('NULL xref')
+ print("NULL xref")
continue
self._xrefs.append(ptr.xref)
@@ -335,15 +429,15 @@ class Xrelfo(dict):
def load_json(self, fd):
data = json.load(fd)
- for uid, items in data['refs'].items():
- myitems = self['refs'].setdefault(uid, [])
+ for uid, items in data["refs"].items():
+ myitems = self["refs"].setdefault(uid, [])
for item in items:
if item in myitems:
continue
myitems.append(item)
- for cmd, items in data['cli'].items():
- self['cli'].setdefault(cmd, {}).update(items)
+ for cmd, items in data["cli"].items():
+ self["cli"].setdefault(cmd, {}).update(items)
return data
@@ -351,23 +445,33 @@ class Xrelfo(dict):
for xref in self._xrefs:
yield from xref.check(checks)
+
def main():
- argp = argparse.ArgumentParser(description = 'FRR xref ELF extractor')
- argp.add_argument('-o', dest='output', type=str, help='write JSON output')
- argp.add_argument('--out-by-file', type=str, help='write by-file JSON output')
- argp.add_argument('-Wlog-format', action='store_const', const=True)
- argp.add_argument('-Wlog-args', action='store_const', const=True)
- argp.add_argument('-Werror', action='store_const', const=True)
- argp.add_argument('--profile', action='store_const', const=True)
- argp.add_argument('binaries', metavar='BINARY', nargs='+', type=str, help='files to read (ELF files or libtool objects)')
+ argp = argparse.ArgumentParser(description="FRR xref ELF extractor")
+ argp.add_argument("-o", dest="output", type=str, help="write JSON output")
+ argp.add_argument("--out-by-file", type=str, help="write by-file JSON output")
+ argp.add_argument("-c", dest="vtysh_cmds", type=str, help="write vtysh_cmd.c")
+ argp.add_argument("-Wlog-format", action="store_const", const=True)
+ argp.add_argument("-Wlog-args", action="store_const", const=True)
+ argp.add_argument("-Werror", action="store_const", const=True)
+ argp.add_argument("--profile", action="store_const", const=True)
+ argp.add_argument(
+ "binaries",
+ metavar="BINARY",
+ nargs="+",
+ type=str,
+ help="files to read (ELF files or libtool objects)",
+ )
args = argp.parse_args()
if args.profile:
import cProfile
- cProfile.runctx('_main(args)', globals(), {'args': args}, sort='cumtime')
+
+ cProfile.runctx("_main(args)", globals(), {"args": args}, sort="cumtime")
else:
_main(args)
+
def _main(args):
errors = 0
xrelfo = Xrelfo()
@@ -377,52 +481,59 @@ def _main(args):
xrelfo.load_file(fn)
except:
errors += 1
- sys.stderr.write('while processing %s:\n' % (fn))
+ sys.stderr.write("while processing %s:\n" % (fn))
traceback.print_exc()
for option in dir(args):
- if option.startswith('W') and option != 'Werror':
+ if option.startswith("W") and option != "Werror":
checks = sorted(xrelfo.check(args))
- sys.stderr.write(''.join([c[-1] for c in checks]))
+ sys.stderr.write("".join([c[-1] for c in checks]))
if args.Werror and len(checks) > 0:
errors += 1
break
-
- refs = xrelfo['refs']
+ refs = xrelfo["refs"]
counts = {}
for k, v in refs.items():
- strs = set([i['fmtstring'] for i in v])
+ strs = set([i["fmtstring"] for i in v])
if len(strs) != 1:
- print('\033[31;1m%s\033[m' % k)
+ print("\033[31;1m%s\033[m" % k)
counts[k] = len(v)
out = xrelfo
outbyfile = {}
for uid, locs in refs.items():
for loc in locs:
- filearray = outbyfile.setdefault(loc['file'], [])
+ filearray = outbyfile.setdefault(loc["file"], [])
loc = dict(loc)
- del loc['file']
+ del loc["file"]
filearray.append(loc)
for k in outbyfile.keys():
- outbyfile[k] = sorted(outbyfile[k], key=lambda x: x['line'])
+ outbyfile[k] = sorted(outbyfile[k], key=lambda x: x["line"])
if errors:
sys.exit(1)
if args.output:
- with open(args.output + '.tmp', 'w') as fd:
- json.dump(out, fd, indent=2, sort_keys=True)
- os.rename(args.output + '.tmp', args.output)
+ with open(args.output + ".tmp", "w") as fd:
+ json.dump(out, fd, indent=2, sort_keys=True, **json_dump_args)
+ os.rename(args.output + ".tmp", args.output)
if args.out_by_file:
- with open(args.out_by_file + '.tmp', 'w') as fd:
- json.dump(outbyfile, fd, indent=2, sort_keys=True)
- os.rename(args.out_by_file + '.tmp', args.out_by_file)
+ with open(args.out_by_file + ".tmp", "w") as fd:
+ json.dump(outbyfile, fd, indent=2, sort_keys=True, **json_dump_args)
+ os.rename(args.out_by_file + ".tmp", args.out_by_file)
+
+ if args.vtysh_cmds:
+ with open(args.vtysh_cmds + ".tmp", "w") as fd:
+ CommandEntry.run(out, fd)
+ os.rename(args.vtysh_cmds + ".tmp", args.vtysh_cmds)
+ if args.Werror and CommandEntry.warn_counter:
+ sys.exit(1)
+
-if __name__ == '__main__':
+if __name__ == "__main__":
main()
diff --git a/redhat/frr.pam b/redhat/frr.pam
index 5cef5d9d7..17a62f199 100644
--- a/redhat/frr.pam
+++ b/redhat/frr.pam
@@ -5,6 +5,7 @@
# Only allow root (and possibly wheel) to use this because enable access
# is unrestricted.
auth sufficient pam_rootok.so
+account sufficient pam_rootok.so
# Uncomment the following line to implicitly trust users in the "wheel" group.
#auth sufficient pam_wheel.so trust use_uid
diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in
index 8f469d2a0..afe75e1f2 100644
--- a/redhat/frr.spec.in
+++ b/redhat/frr.spec.in
@@ -469,7 +469,7 @@ ln -s %{_sbindir}/frrinit.sh %{buildroot}%{_initddir}/frr
install %{zeb_src}/tools/etc/frr/daemons %{buildroot}%{_sysconfdir}/frr
install %{zeb_src}/tools/etc/frr/frr.conf %{buildroot}%{_sysconfdir}/frr/frr.conf.template
install -m644 %{zeb_rh_src}/frr.pam %{buildroot}%{_sysconfdir}/pam.d/frr
-install -m644 %{zeb_rh_src}/frr.logrotate %{buildroot}%{_sysconfdir}/logrotate.d/frr
+install -m644 %{zeb_src}/tools/etc/logrotate.d/frr %{buildroot}%{_sysconfdir}/logrotate.d/frr
install -d -m750 %{buildroot}%{rundir}
%if 0%{?rhel} > 7 || 0%{?fedora} > 29
diff --git a/ripd/rip_cli.c b/ripd/rip_cli.c
index 73442bf16..34ea21672 100644
--- a/ripd/rip_cli.c
+++ b/ripd/rip_cli.c
@@ -30,9 +30,7 @@
#include "ripd/ripd.h"
#include "ripd/rip_nb.h"
-#ifndef VTYSH_EXTRACT_PL
#include "ripd/rip_cli_clippy.c"
-#endif
/*
* XPath: /frr-ripd:ripd/instance
diff --git a/ripd/rip_debug.c b/ripd/rip_debug.c
index 871ee8e87..ded62812a 100644
--- a/ripd/rip_debug.c
+++ b/ripd/rip_debug.c
@@ -55,6 +55,8 @@ DEFUN_NOSH (show_debugging_rip,
if (IS_RIP_DEBUG_ZEBRA)
vty_out(vty, " RIP zebra debugging is on\n");
+ cmd_show_lib_debugs(vty);
+
return CMD_SUCCESS;
}
diff --git a/ripd/ripd.c b/ripd/ripd.c
index 8a321d9a9..8e02f1a6c 100644
--- a/ripd/ripd.c
+++ b/ripd/ripd.c
@@ -3551,10 +3551,18 @@ static int rip_vrf_new(struct vrf *vrf)
static int rip_vrf_delete(struct vrf *vrf)
{
+ struct rip *rip;
+
if (IS_RIP_DEBUG_EVENT)
zlog_debug("%s: VRF deleted: %s(%u)", __func__, vrf->name,
vrf->vrf_id);
+ rip = rip_lookup_by_vrf_name(vrf->name);
+ if (!rip)
+ return 0;
+
+ rip_clean(rip);
+
return 0;
}
diff --git a/ripd/subdir.am b/ripd/subdir.am
index b00c37588..98cc765c9 100644
--- a/ripd/subdir.am
+++ b/ripd/subdir.am
@@ -4,11 +4,6 @@
if RIPD
sbin_PROGRAMS += ripd/ripd
-vtysh_scan += \
- ripd/rip_cli.c \
- ripd/rip_debug.c \
- ripd/ripd.c \
- # end
vtysh_daemons += ripd
if SNMP
diff --git a/ripngd/ripng_cli.c b/ripngd/ripng_cli.c
index ded2f4358..049a392dd 100644
--- a/ripngd/ripng_cli.c
+++ b/ripngd/ripng_cli.c
@@ -30,9 +30,7 @@
#include "ripngd/ripngd.h"
#include "ripngd/ripng_nb.h"
-#ifndef VTYSH_EXTRACT_PL
#include "ripngd/ripng_cli_clippy.c"
-#endif
/*
* XPath: /frr-ripngd:ripngd/instance
diff --git a/ripngd/ripng_debug.c b/ripngd/ripng_debug.c
index 539c01b3e..d36327cb7 100644
--- a/ripngd/ripng_debug.c
+++ b/ripngd/ripng_debug.c
@@ -56,6 +56,8 @@ DEFUN_NOSH (show_debugging_ripng,
if (IS_RIPNG_DEBUG_ZEBRA)
vty_out(vty, " RIPng zebra debugging is on\n");
+ cmd_show_lib_debugs(vty);
+
return CMD_SUCCESS;
}
diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c
index 1e7a13d7d..755debd0a 100644
--- a/ripngd/ripngd.c
+++ b/ripngd/ripngd.c
@@ -2581,10 +2581,17 @@ static int ripng_vrf_new(struct vrf *vrf)
static int ripng_vrf_delete(struct vrf *vrf)
{
+ struct ripng *ripng;
+
if (IS_RIPNG_DEBUG_EVENT)
zlog_debug("%s: VRF deleted: %s(%u)", __func__, vrf->name,
vrf->vrf_id);
+ ripng = ripng_lookup_by_vrf_name(vrf->name);
+ if (!ripng)
+ return 0;
+
+ ripng_clean(ripng);
return 0;
}
diff --git a/ripngd/subdir.am b/ripngd/subdir.am
index a4db3e5a6..162426c58 100644
--- a/ripngd/subdir.am
+++ b/ripngd/subdir.am
@@ -4,11 +4,6 @@
if RIPNGD
sbin_PROGRAMS += ripngd/ripngd
-vtysh_scan += \
- ripngd/ripng_cli.c \
- ripngd/ripng_debug.c \
- ripngd/ripngd.c \
- # end
vtysh_daemons += ripngd
man8 += $(MANBUILD)/frr-ripngd.8
endif
diff --git a/sharpd/sharp_nht.c b/sharpd/sharp_nht.c
index a90387186..b032da6a1 100644
--- a/sharpd/sharp_nht.c
+++ b/sharpd/sharp_nht.c
@@ -124,6 +124,24 @@ static void sharp_nhgroup_add_cb(const char *name)
sharp_nhg_rb_add(&nhg_head, snhg);
}
+static void sharp_nhgroup_modify_cb(const struct nexthop_group_cmd *nhgc)
+{
+ struct sharp_nhg lookup;
+ struct sharp_nhg *snhg;
+ struct nexthop_group_cmd *bnhgc = NULL;
+
+ strlcpy(lookup.name, nhgc->name, sizeof(lookup.name));
+ snhg = sharp_nhg_rb_find(&nhg_head, &lookup);
+
+ if (!nhgc->nhg.nexthop)
+ return;
+
+ if (nhgc->backup_list_name[0])
+ bnhgc = nhgc_find(nhgc->backup_list_name);
+
+ nhg_add(snhg->id, &nhgc->nhg, (bnhgc ? &bnhgc->nhg : NULL));
+}
+
static void sharp_nhgroup_add_nexthop_cb(const struct nexthop_group_cmd *nhgc,
const struct nexthop *nhop)
{
@@ -215,7 +233,8 @@ void sharp_nhgroup_init(void)
sharp_nhg_rb_init(&nhg_head);
nhg_id = zclient_get_nhg_start(ZEBRA_ROUTE_SHARP);
- nexthop_group_init(sharp_nhgroup_add_cb, sharp_nhgroup_add_nexthop_cb,
+ nexthop_group_init(sharp_nhgroup_add_cb, sharp_nhgroup_modify_cb,
+ sharp_nhgroup_add_nexthop_cb,
sharp_nhgroup_del_nexthop_cb,
sharp_nhgroup_delete_cb);
}
diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c
index 3853df7cb..164a0fd21 100644
--- a/sharpd/sharp_vty.c
+++ b/sharpd/sharp_vty.c
@@ -37,9 +37,7 @@
#include "sharpd/sharp_zebra.h"
#include "sharpd/sharp_nht.h"
#include "sharpd/sharp_vty.h"
-#ifndef VTYSH_EXTRACT_PL
#include "sharpd/sharp_vty_clippy.c"
-#endif
DEFINE_MTYPE_STATIC(SHARPD, SRV6_LOCATOR, "SRv6 Locator");
@@ -432,7 +430,8 @@ DEFPY (install_seg6local_routes,
End_T$seg6l_endt (1-4294967295)$seg6l_endt_table|\
End_DX4$seg6l_enddx4 A.B.C.D$seg6l_enddx4_nh4|\
End_DT6$seg6l_enddt6 (1-4294967295)$seg6l_enddt6_table|\
- End_DT4$seg6l_enddt4 (1-4294967295)$seg6l_enddt4_table>\
+ End_DT4$seg6l_enddt4 (1-4294967295)$seg6l_enddt4_table|\
+ End_DT46$seg6l_enddt46 (1-4294967295)$seg6l_enddt46_table>\
(1-1000000)$routes [repeat (2-1000)$rpt]",
"Sharp routing Protocol\n"
"install some routes\n"
@@ -453,6 +452,8 @@ DEFPY (install_seg6local_routes,
"Redirect table id to use\n"
"SRv6 End.DT4 function to use\n"
"Redirect table id to use\n"
+ "SRv6 End.DT46 function to use\n"
+ "Redirect table id to use\n"
"How many to create\n"
"Should we repeat this command\n"
"How many times to repeat this command\n")
@@ -508,6 +509,9 @@ DEFPY (install_seg6local_routes,
} else if (seg6l_enddt4) {
action = ZEBRA_SEG6_LOCAL_ACTION_END_DT4;
ctx.table = seg6l_enddt4_table;
+ } else if (seg6l_enddt46) {
+ action = ZEBRA_SEG6_LOCAL_ACTION_END_DT46;
+ ctx.table = seg6l_enddt46_table;
} else {
action = ZEBRA_SEG6_LOCAL_ACTION_END;
}
@@ -615,6 +619,8 @@ DEFUN_NOSH (show_debugging_sharpd,
{
vty_out(vty, "Sharp debugging status:\n");
+ cmd_show_lib_debugs(vty);
+
return CMD_SUCCESS;
}
diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c
index b40c2c622..9d343576d 100644
--- a/sharpd/sharp_zebra.c
+++ b/sharpd/sharp_zebra.c
@@ -550,6 +550,9 @@ void nhg_add(uint32_t id, const struct nexthop_group *nhg,
bool is_valid = true;
api_nhg.id = id;
+
+ api_nhg.resilience = nhg->nhgr;
+
for (ALL_NEXTHOPS_PTR(nhg, nh)) {
if (api_nhg.nexthop_num >= MULTIPATH_NUM) {
zlog_warn(
diff --git a/sharpd/subdir.am b/sharpd/subdir.am
index acf4fe5d0..3eb8d1d3b 100644
--- a/sharpd/subdir.am
+++ b/sharpd/subdir.am
@@ -5,7 +5,6 @@
if SHARPD
noinst_LIBRARIES += sharpd/libsharp.a
sbin_PROGRAMS += sharpd/sharpd
-vtysh_scan += sharpd/sharp_vty.c
vtysh_daemons += sharpd
man8 += $(MANBUILD)/frr-sharpd.8
endif
diff --git a/snapcraft/snapcraft.yaml.in b/snapcraft/snapcraft.yaml.in
index 9729be7b9..f634b59c7 100644
--- a/snapcraft/snapcraft.yaml.in
+++ b/snapcraft/snapcraft.yaml.in
@@ -272,7 +272,7 @@ parts:
- zlib1g
prime:
- lib/librtr.so*
- - usr/lib/x86_64-linux-gnu/libssh.so*
+ - usr/lib/$SNAPCRAFT_ARCH_TRIPLET/libssh.so*
source: https://github.com/rtrlib/rtrlib.git
source-type: git
source-tag: v0.8.0
diff --git a/staticd/static_main.c b/staticd/static_main.c
index 7badd5004..79686158c 100644
--- a/staticd/static_main.c
+++ b/staticd/static_main.c
@@ -79,6 +79,7 @@ static void sigint(void)
static_vrf_terminate();
+ static_zebra_stop();
frr_fini();
exit(0);
diff --git a/staticd/static_vty.c b/staticd/static_vty.c
index c0ace0e25..94a349347 100644
--- a/staticd/static_vty.c
+++ b/staticd/static_vty.c
@@ -36,9 +36,7 @@
#include "static_vty.h"
#include "static_routes.h"
#include "static_debug.h"
-#ifndef VTYSH_EXTRACT_PL
#include "staticd/static_vty_clippy.c"
-#endif
#include "static_nb.h"
#define STATICD_STR "Static route daemon\n"
@@ -1301,6 +1299,8 @@ DEFUN_NOSH (show_debugging_static,
static_debug_status_write(vty);
+ cmd_show_lib_debugs(vty);
+
return CMD_SUCCESS;
}
diff --git a/staticd/subdir.am b/staticd/subdir.am
index 62969a0a2..bb0fc95bc 100644
--- a/staticd/subdir.am
+++ b/staticd/subdir.am
@@ -5,7 +5,6 @@
if STATICD
noinst_LIBRARIES += staticd/libstatic.a
sbin_PROGRAMS += staticd/staticd
-vtysh_scan += staticd/static_vty.c
vtysh_daemons += staticd
man8 += $(MANBUILD)/frr-staticd.8
endif
diff --git a/tests/isisd/test_isis_spf.refout b/tests/isisd/test_isis_spf.refout
index bdd5b2e43..23d41b9e5 100644
--- a/tests/isisd/test_isis_spf.refout
+++ b/tests/isisd/test_isis_spf.refout
@@ -823,7 +823,7 @@ IS-IS L1 IPv4 routing table:
Prefix Metric Interface Nexthop Label(s)
----------------------------------------------------------
- 10.0.255.2/32 40 - rt2 implicit-null
+ 10.0.255.2/32 50 - rt2 implicit-null
IS-IS paths to level-1 routers that speak IPv6
Vertex Type Metric Next-Hop Interface Parent
@@ -859,7 +859,7 @@ IS-IS L1 IPv6 routing table:
Prefix Metric Interface Nexthop Label(s)
------------------------------------------------------------
- 2001:db8::2/128 40 - rt2 implicit-null
+ 2001:db8::2/128 50 - rt2 implicit-null
test# test isis topology 2 root rt4 lfa system-id rt6
IS-IS paths to level-1 routers that speak IP
@@ -896,7 +896,7 @@ IS-IS L1 IPv4 routing table:
Prefix Metric Interface Nexthop Label(s)
-----------------------------------------------------
- 10.0.255.6/32 20 - rt5 16060
+ 10.0.255.6/32 30 - rt5 16060
IS-IS paths to level-1 routers that speak IPv6
Vertex Type Metric Next-Hop Interface Parent
@@ -932,7 +932,7 @@ IS-IS L1 IPv6 routing table:
Prefix Metric Interface Nexthop Label(s)
-------------------------------------------------------
- 2001:db8::6/128 20 - rt5 16061
+ 2001:db8::6/128 30 - rt5 16061
test# test isis topology 3 root rt1 lfa system-id rt2
IS-IS paths to level-1 routers that speak IP
@@ -967,10 +967,10 @@ IS-IS L1 IPv4 routing table:
Prefix Metric Interface Nexthop Label(s)
-----------------------------------------------------
- 10.0.255.2/32 20 - rt3 16020
- 10.0.255.4/32 30 - rt3 16040
- 10.0.255.5/32 40 - rt3 16050
- 10.0.255.6/32 40 - rt3 16060
+ 10.0.255.2/32 30 - rt3 16020
+ 10.0.255.4/32 40 - rt3 16040
+ 10.0.255.5/32 50 - rt3 16050
+ 10.0.255.6/32 50 - rt3 16060
IS-IS paths to level-1 routers that speak IPv6
Vertex Type Metric Next-Hop Interface Parent
@@ -1017,7 +1017,7 @@ IS-IS L1 IPv4 routing table:
Prefix Metric Interface Nexthop Label(s)
-----------------------------------------------------
- 10.0.255.3/32 20 - rt2 16030
+ 10.0.255.3/32 30 - rt2 16030
IS-IS paths to level-1 routers that speak IPv6
Vertex Type Metric Next-Hop Interface Parent
@@ -1085,17 +1085,17 @@ IS-IS L1 IPv4 routing table:
Prefix Metric Interface Nexthop Label(s)
-----------------------------------------------------------
- 10.0.255.2/32 40 - rt2 implicit-null
- 10.0.255.3/32 50 - rt2 16030
- 10.0.255.4/32 60 - rt2 16040
- 10.0.255.5/32 50 - rt2 16050
- 10.0.255.6/32 60 - rt2 16060
- 10.0.255.7/32 70 - rt2 16070
- 10.0.255.8/32 60 - rt2 16080
- 10.0.255.9/32 70 - rt2 16090
- 10.0.255.10/32 80 - rt2 16100
- 10.0.255.11/32 70 - rt2 16110
- 10.0.255.12/32 80 - rt2 16120
+ 10.0.255.2/32 50 - rt2 implicit-null
+ 10.0.255.3/32 60 - rt2 16030
+ 10.0.255.4/32 70 - rt2 16040
+ 10.0.255.5/32 60 - rt2 16050
+ 10.0.255.6/32 70 - rt2 16060
+ 10.0.255.7/32 80 - rt2 16070
+ 10.0.255.8/32 70 - rt2 16080
+ 10.0.255.9/32 80 - rt2 16090
+ 10.0.255.10/32 90 - rt2 16100
+ 10.0.255.11/32 80 - rt2 16110
+ 10.0.255.12/32 90 - rt2 16120
IS-IS paths to level-1 routers that speak IPv6
Vertex Type Metric Next-Hop Interface Parent
@@ -1173,10 +1173,10 @@ IS-IS L1 IPv4 routing table:
Prefix Metric Interface Nexthop Label(s)
------------------------------------------------------
- 10.0.255.8/32 40 - rt10 16080
- 10.0.255.9/32 50 - rt10 16090
- 10.0.255.11/32 30 - rt10 16110
- 10.0.255.12/32 40 - rt10 16120
+ 10.0.255.8/32 50 - rt10 16080
+ 10.0.255.9/32 60 - rt10 16090
+ 10.0.255.11/32 40 - rt10 16110
+ 10.0.255.12/32 50 - rt10 16120
IS-IS paths to level-1 routers that speak IPv6
Vertex Type Metric Next-Hop Interface Parent
@@ -1252,7 +1252,7 @@ IS-IS L1 IPv4 routing table:
Prefix Metric Interface Nexthop Label(s)
------------------------------------------------------
- 10.0.255.10/32 30 - rt7 16100
+ 10.0.255.10/32 40 - rt7 16100
IS-IS paths to level-1 routers that speak IPv6
Vertex Type Metric Next-Hop Interface Parent
@@ -1313,14 +1313,14 @@ IS-IS L1 IPv4 routing table:
Prefix Metric Interface Nexthop Label(s)
----------------------------------------------------------
- 10.0.255.1/32 120 - rt4 16010
- 10.0.255.2/32 110 - rt4 16020
- 10.0.255.4/32 100 - rt4 implicit-null
- 10.0.255.5/32 110 - rt4 16050
- 10.0.255.6/32 130 - rt4 16060
- 10.0.255.7/32 130 - rt4 16070
- 10.0.255.8/32 130 - rt4 16080
- 10.0.255.9/32 120 - rt4 16090
+ 10.0.255.1/32 130 - rt4 16010
+ 10.0.255.2/32 120 - rt4 16020
+ 10.0.255.4/32 110 - rt4 implicit-null
+ 10.0.255.5/32 120 - rt4 16050
+ 10.0.255.6/32 140 - rt4 16060
+ 10.0.255.7/32 140 - rt4 16070
+ 10.0.255.8/32 140 - rt4 16080
+ 10.0.255.9/32 130 - rt4 16090
IS-IS paths to level-1 routers that speak IPv6
Vertex Type Metric Next-Hop Interface Parent
@@ -1366,14 +1366,14 @@ IS-IS L1 IPv6 routing table:
Prefix Metric Interface Nexthop Label(s)
------------------------------------------------------------
- 2001:db8::1/128 120 - rt4 16011
- 2001:db8::2/128 110 - rt4 16021
- 2001:db8::4/128 100 - rt4 implicit-null
- 2001:db8::5/128 110 - rt4 16051
- 2001:db8::6/128 130 - rt4 16061
- 2001:db8::7/128 130 - rt4 16071
- 2001:db8::8/128 130 - rt4 16081
- 2001:db8::9/128 120 - rt4 16091
+ 2001:db8::1/128 130 - rt4 16011
+ 2001:db8::2/128 120 - rt4 16021
+ 2001:db8::4/128 110 - rt4 implicit-null
+ 2001:db8::5/128 120 - rt4 16051
+ 2001:db8::6/128 140 - rt4 16061
+ 2001:db8::7/128 140 - rt4 16071
+ 2001:db8::8/128 140 - rt4 16081
+ 2001:db8::9/128 130 - rt4 16091
test# test isis topology 10 root rt8 lfa system-id rt5
IS-IS paths to level-1 routers that speak IP
@@ -1414,15 +1414,15 @@ IS-IS L1 IPv4 routing table:
Prefix Metric Interface Nexthop Label(s)
-----------------------------------------------------
- 10.0.255.1/32 80 - rt6 16010
+ 10.0.255.1/32 90 - rt6 16010
- rt7 16010
- 10.0.255.2/32 90 - rt6 16020
+ 10.0.255.2/32 100 - rt6 16020
- rt7 16020
- 10.0.255.3/32 60 - rt6 16030
+ 10.0.255.3/32 70 - rt6 16030
- rt7 16030
- 10.0.255.4/32 60 - rt6 16040
+ 10.0.255.4/32 70 - rt6 16040
- rt7 16040
- 10.0.255.5/32 100 - rt6 16050
+ 10.0.255.5/32 110 - rt6 16050
- rt7 16050
IS-IS paths to level-1 routers that speak IPv6
@@ -1463,15 +1463,15 @@ IS-IS L1 IPv6 routing table:
Prefix Metric Interface Nexthop Label(s)
-------------------------------------------------------
- 2001:db8::1/128 80 - rt6 16011
+ 2001:db8::1/128 90 - rt6 16011
- rt7 16011
- 2001:db8::2/128 90 - rt6 16021
+ 2001:db8::2/128 100 - rt6 16021
- rt7 16021
- 2001:db8::3/128 60 - rt6 16031
+ 2001:db8::3/128 70 - rt6 16031
- rt7 16031
- 2001:db8::4/128 60 - rt6 16041
+ 2001:db8::4/128 70 - rt6 16041
- rt7 16041
- 2001:db8::5/128 100 - rt6 16051
+ 2001:db8::5/128 110 - rt6 16051
- rt7 16051
test# test isis topology 11 root rt3 lfa system-id rt5
@@ -1511,8 +1511,8 @@ IS-IS L1 IPv4 routing table:
Prefix Metric Interface Nexthop Label(s)
-----------------------------------------------------
- 10.0.255.5/32 30 - rt2 16050
- 10.0.255.6/32 30 - rt2 16060
+ 10.0.255.5/32 40 - rt2 16050
+ 10.0.255.6/32 40 - rt2 16060
IS-IS paths to level-1 routers that speak IPv6
Vertex Type Metric Next-Hop Interface Parent
@@ -1550,8 +1550,8 @@ IS-IS L1 IPv6 routing table:
Prefix Metric Interface Nexthop Label(s)
-------------------------------------------------------
- 2001:db8::5/128 30 - rt2 16051
- 2001:db8::6/128 30 - rt2 16061
+ 2001:db8::5/128 40 - rt2 16051
+ 2001:db8::6/128 40 - rt2 16061
test# test isis topology 13 root rt4 lfa system-id rt3
IS-IS paths to level-1 routers that speak IP
@@ -1593,10 +1593,10 @@ IS-IS L1 IPv4 routing table:
Prefix Metric Interface Nexthop Label(s)
----------------------------------------------------------
- 10.0.255.3/32 110 - rt5 16030
- 10.0.255.5/32 100 - rt5 implicit-null
- 10.0.255.6/32 120 - rt5 16060
- 10.0.255.7/32 110 - rt5 16070
+ 10.0.255.3/32 120 - rt5 16030
+ 10.0.255.5/32 110 - rt5 implicit-null
+ 10.0.255.6/32 130 - rt5 16060
+ 10.0.255.7/32 120 - rt5 16070
IS-IS paths to level-1 routers that speak IPv6
Vertex Type Metric Next-Hop Interface Parent
@@ -1699,7 +1699,7 @@ IS-IS L1 IPv4 routing table:
Prefix Metric Interface Nexthop Label(s)
-----------------------------------------------------
- 10.0.255.2/32 20 - rt3 -
+ 10.0.255.2/32 30 - rt3 -
IS-IS paths to level-1 routers that speak IPv6
Vertex Type Metric Next-Hop Interface Parent
@@ -1731,7 +1731,7 @@ IS-IS L1 IPv6 routing table:
Prefix Metric Interface Nexthop Label(s)
-------------------------------------------------------
- 2001:db8::2/128 20 - rt3 -
+ 2001:db8::2/128 30 - rt3 -
test# test isis topology 14 root rt5 lfa system-id rt4
IS-IS paths to level-1 routers that speak IP
@@ -1765,10 +1765,10 @@ IS-IS L1 IPv4 routing table:
Prefix Metric Interface Nexthop Label(s)
-----------------------------------------------------
- 10.0.255.1/32 60 - rt3 -
- 10.0.255.2/32 60 - rt3 -
- 10.0.255.3/32 50 - rt3 -
- 10.0.255.4/32 60 - rt3 -
+ 10.0.255.1/32 70 - rt3 -
+ 10.0.255.2/32 70 - rt3 -
+ 10.0.255.3/32 60 - rt3 -
+ 10.0.255.4/32 70 - rt3 -
IS-IS paths to level-1 routers that speak IPv6
Vertex Type Metric Next-Hop Interface Parent
@@ -1801,10 +1801,10 @@ IS-IS L1 IPv6 routing table:
Prefix Metric Interface Nexthop Label(s)
-------------------------------------------------------
- 2001:db8::1/128 60 - rt3 -
- 2001:db8::2/128 60 - rt3 -
- 2001:db8::3/128 50 - rt3 -
- 2001:db8::4/128 60 - rt3 -
+ 2001:db8::1/128 70 - rt3 -
+ 2001:db8::2/128 70 - rt3 -
+ 2001:db8::3/128 60 - rt3 -
+ 2001:db8::4/128 70 - rt3 -
test#
test# test isis topology 1 root rt1 remote-lfa system-id rt2
@@ -2174,11 +2174,11 @@ IS-IS L1 IPv4 routing table:
Prefix Metric Interface Nexthop Label(s)
-----------------------------------------------------
- 10.0.255.1/32 40 - rt3 16010
+ 10.0.255.1/32 50 - rt3 16010
- rt6 16010
- 10.0.255.2/32 30 - rt3 16020
+ 10.0.255.2/32 40 - rt3 16020
- rt6 16020
- 10.0.255.4/32 20 - rt3 16040
+ 10.0.255.4/32 30 - rt3 16040
- rt6 16040
test# test isis topology 3 root rt5 remote-lfa system-id rt3 ipv4-only
@@ -2535,13 +2535,13 @@ IS-IS L1 IPv4 routing table:
Prefix Metric Interface Nexthop Label(s)
--------------------------------------------------------
- 10.0.255.1/32 50 - rt10 16010
+ 10.0.255.1/32 60 - rt10 16010
10.0.255.2/32 60 - rt12 50900/16020
10.0.255.3/32 70 - rt12 50900/16030
- 10.0.255.4/32 40 - rt10 16040
+ 10.0.255.4/32 50 - rt10 16040
10.0.255.5/32 50 - rt12 50900/16050
10.0.255.6/32 60 - rt12 50900/16060
- 10.0.255.7/32 30 - rt10 16070
+ 10.0.255.7/32 40 - rt10 16070
10.0.255.8/32 40 - rt12 50900/16080
test# test isis topology 7 root rt6 remote-lfa system-id rt5 ipv4-only
@@ -2671,13 +2671,13 @@ IS-IS L1 IPv4 routing table:
Prefix Metric Interface Nexthop Label(s)
------------------------------------------------------
- 10.0.255.1/32 70 - rt9 16010
- 10.0.255.4/32 60 - rt9 16040
- 10.0.255.5/32 50 - rt9 16050
- 10.0.255.7/32 50 - rt9 16070
- 10.0.255.8/32 40 - rt9 16080
- 10.0.255.10/32 60 - rt9 16100
- 10.0.255.11/32 50 - rt9 16110
+ 10.0.255.1/32 80 - rt9 16010
+ 10.0.255.4/32 70 - rt9 16040
+ 10.0.255.5/32 60 - rt9 16050
+ 10.0.255.7/32 60 - rt9 16070
+ 10.0.255.8/32 50 - rt9 16080
+ 10.0.255.10/32 70 - rt9 16100
+ 10.0.255.11/32 60 - rt9 16110
test# test isis topology 8 root rt2 remote-lfa system-id rt5 ipv4-only
P-space (self):
@@ -2863,14 +2863,14 @@ IS-IS L1 IPv4 routing table:
Prefix Metric Interface Nexthop Label(s)
----------------------------------------------------------
- 10.0.255.1/32 50 - rt1 implicit-null
+ 10.0.255.1/32 60 - rt1 implicit-null
- rt3 16010
- 10.0.255.3/32 50 - rt1 16030
+ 10.0.255.3/32 60 - rt1 16030
- rt3 implicit-null
10.0.255.4/32 80 - rt3 50500/16040
- 10.0.255.5/32 60 - rt1 16050
+ 10.0.255.5/32 70 - rt1 16050
- rt3 16050
- 10.0.255.6/32 70 - rt3 16060
+ 10.0.255.6/32 80 - rt3 16060
P-space (self):
@@ -2941,14 +2941,14 @@ IS-IS L1 IPv6 routing table:
Prefix Metric Interface Nexthop Label(s)
------------------------------------------------------------
- 2001:db8::1/128 50 - rt1 implicit-null
+ 2001:db8::1/128 60 - rt1 implicit-null
- rt3 16011
- 2001:db8::3/128 50 - rt1 16031
+ 2001:db8::3/128 60 - rt1 16031
- rt3 implicit-null
2001:db8::4/128 80 - rt3 50500/16041
- 2001:db8::5/128 60 - rt1 16051
+ 2001:db8::5/128 70 - rt1 16051
- rt3 16051
- 2001:db8::6/128 70 - rt3 16061
+ 2001:db8::6/128 80 - rt3 16061
test# test isis topology 13 root rt1 remote-lfa system-id rt3 ipv4-only
P-space (self):
diff --git a/tests/topotests/all_protocol_startup/r1/ospf6d.conf b/tests/topotests/all_protocol_startup/r1/ospf6d.conf
index 2e4518665..33c26501b 100644
--- a/tests/topotests/all_protocol_startup/r1/ospf6d.conf
+++ b/tests/topotests/all_protocol_startup/r1/ospf6d.conf
@@ -6,6 +6,7 @@ log file ospf6d.log
! debug ospf6 neighbor
!
interface r1-eth4
+ ipv6 ospf6 hello-interval 1
!
router ospf6
ospf6 router-id 192.168.0.1
diff --git a/tests/topotests/all_protocol_startup/r1/ospfd.conf b/tests/topotests/all_protocol_startup/r1/ospfd.conf
index 188f810f8..61af44a4d 100644
--- a/tests/topotests/all_protocol_startup/r1/ospfd.conf
+++ b/tests/topotests/all_protocol_startup/r1/ospfd.conf
@@ -3,6 +3,15 @@ log file ospfd.log
! debug ospf event
! debug ospf zebra
!
+!
+interface r1-eth0
+ ip ospf hello-interval 1
+ ip ospf dead-interval 5
+!
+interface r1-eth3
+ ip ospf hello-interval 1
+ ip ospf dead-interval 5
+!
router ospf
ospf router-id 192.168.0.1
log-adjacency-changes
diff --git a/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post4.1.ref b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post4.1.ref
index b38701a53..b2e8de5ce 100644
--- a/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post4.1.ref
+++ b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post4.1.ref
@@ -5,5 +5,5 @@ Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
RPKI validation codes: V valid, I invalid, N Not found
- Network Next Hop Metric LocPrf Weight Path
-*> 192.168.0.0 0.0.0.0 0 32768 i
+ Network Next Hop Metric LocPrf Weight Path
+ *> 192.168.0.0 0.0.0.0 0 32768 i
diff --git a/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post5.0.ref b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post5.0.ref
index 82b64c0d9..7bee70418 100644
--- a/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post5.0.ref
+++ b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post5.0.ref
@@ -5,5 +5,5 @@ Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
RPKI validation codes: V valid, I invalid, N Not found
- Network Next Hop Metric LocPrf Weight Path
-*> 192.168.0.0/24 0.0.0.0 0 32768 i
+ Network Next Hop Metric LocPrf Weight Path
+ *> 192.168.0.0/24 0.0.0.0 0 32768 i
diff --git a/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post6.1.ref b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post6.1.ref
index fd333b308..31071e760 100644
--- a/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post6.1.ref
+++ b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post6.1.ref
@@ -6,5 +6,5 @@ Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
RPKI validation codes: V valid, I invalid, N Not found
- Network Next Hop Metric LocPrf Weight Path
-*> 192.168.0.0/24 0.0.0.0 0 32768 i
+ Network Next Hop Metric LocPrf Weight Path
+ *> 192.168.0.0/24 0.0.0.0 0 32768 i
diff --git a/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4.ref b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4.ref
index 3be6cd3d7..53c4793bf 100644
--- a/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4.ref
+++ b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv4.ref
@@ -3,5 +3,5 @@ Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
i internal, r RIB-failure, S Stale, R Removed
Origin codes: i - IGP, e - EGP, ? - incomplete
- Network Next Hop Metric LocPrf Weight Path
-*> 192.168.0.0 0.0.0.0 0 32768 i
+ Network Next Hop Metric LocPrf Weight Path
+ *> 192.168.0.0 0.0.0.0 0 32768 i
diff --git a/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6-post4.1.ref b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6-post4.1.ref
index 20034b740..fe3f0720d 100644
--- a/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6-post4.1.ref
+++ b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6-post4.1.ref
@@ -5,5 +5,5 @@ Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
RPKI validation codes: V valid, I invalid, N Not found
- Network Next Hop Metric LocPrf Weight Path
-*> fc00::/64 :: 0 32768 i
+ Network Next Hop Metric LocPrf Weight Path
+ *> fc00::/64 :: 0 32768 i
diff --git a/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6.ref b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6.ref
index fffee63c6..363b4f534 100644
--- a/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6.ref
+++ b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6.ref
@@ -3,5 +3,5 @@ Status codes: s suppressed, d damped, h history, * valid, > best, = multipath,
i internal, r RIB-failure, S Stale, R Removed
Origin codes: i - IGP, e - EGP, ? - incomplete
- Network Next Hop Metric LocPrf Weight Path
-*> fc00::/64 :: 0 32768 i
+ Network Next Hop Metric LocPrf Weight Path
+ *> fc00::/64 :: 0 32768 i
diff --git a/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6_post6.1.ref b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6_post6.1.ref
index 5b5f8596c..8c3229b45 100644
--- a/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6_post6.1.ref
+++ b/tests/topotests/all_protocol_startup/r1/show_bgp_ipv6_post6.1.ref
@@ -6,5 +6,5 @@ Nexthop codes: @NNN nexthop's vrf id, < announce-nh-self
Origin codes: i - IGP, e - EGP, ? - incomplete
RPKI validation codes: V valid, I invalid, N Not found
- Network Next Hop Metric LocPrf Weight Path
-*> fc00::/64 :: 0 32768 i
+ Network Next Hop Metric LocPrf Weight Path
+ *> fc00::/64 :: 0 32768 i
diff --git a/tests/topotests/all_protocol_startup/r1/show_ip_ospf_interface.ref b/tests/topotests/all_protocol_startup/r1/show_ip_ospf_interface.ref
index ff8567925..cb63da471 100644
--- a/tests/topotests/all_protocol_startup/r1/show_ip_ospf_interface.ref
+++ b/tests/topotests/all_protocol_startup/r1/show_ip_ospf_interface.ref
@@ -7,7 +7,7 @@ r1-eth0 is up
Designated Router (ID) 192.168.0.1 Interface Address 192.168.0.1/24
No backup designated router on this network
Multicast group memberships: OSPFAllRouters OSPFDesignatedRouters
- Timer intervals configured, Hello 10s, Dead 40s, Wait 40s, Retransmit 5
+ Timer intervals configured, Hello 1s, Dead 5s, Wait 5s, Retransmit 5
Hello due in XX.XXXs
Neighbor Count is 0, Adjacent neighbor count is 0
r1-eth3 is up
@@ -19,6 +19,6 @@ r1-eth3 is up
Designated Router (ID) 192.168.0.1 Interface Address 192.168.3.1/26
No backup designated router on this network
Multicast group memberships: OSPFAllRouters OSPFDesignatedRouters
- Timer intervals configured, Hello 10s, Dead 40s, Wait 40s, Retransmit 5
+ Timer intervals configured, Hello 1s, Dead 5s, Wait 5s, Retransmit 5
Hello due in XX.XXXs
Neighbor Count is 0, Adjacent neighbor count is 0
diff --git a/tests/topotests/all_protocol_startup/test_all_protocol_startup.py b/tests/topotests/all_protocol_startup/test_all_protocol_startup.py
index ca8c005f9..2d3e2a759 100644
--- a/tests/topotests/all_protocol_startup/test_all_protocol_startup.py
+++ b/tests/topotests/all_protocol_startup/test_all_protocol_startup.py
@@ -47,6 +47,9 @@ pytestmark = [
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from lib import topotest
from lib.topogen import Topogen, get_topogen
+from lib.common_config import (
+ required_linux_kernel_version,
+)
fatal_error = ""
@@ -301,7 +304,7 @@ def test_converge_protocols():
print("******************************************\n")
# Not really implemented yet - just sleep 60 secs for now
- sleep(60)
+ sleep(5)
# Make sure that all daemons are running
failures = 0
@@ -1591,6 +1594,24 @@ def test_mpls_interfaces():
assert fatal_error == "", fatal_error
+def test_resilient_nexthop_group():
+ net = get_topogen().net
+
+ result = required_linux_kernel_version("5.19")
+ if result is not True:
+ pytest.skip("Kernel requirements are not met, kernel version should be >= 5.19")
+
+ net["r1"].cmd(
+ 'vtysh -c "conf" -c "nexthop-group resilience" -c "resilient buckets 64 idle-timer 128 unbalanced-timer 256" -c "nexthop 1.1.1.1 r1-eth1 onlink" -c "nexthop 1.1.1.2 r1-eth2 onlink"'
+ )
+
+ output = net["r1"].cmd('vtysh -c "show nexthop-group rib sharp"')
+ output = re.findall(r"Buckets", output)
+
+ verify_nexthop_group(185483878)
+ assert len(output) == 1, "Resilient NHG not created in zebra"
+
+
def test_shutdown_check_stderr():
global fatal_error
net = get_topogen().net
diff --git a/tests/topotests/bgp_accept_own/__init__.py b/tests/topotests/bgp_accept_own/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/bgp_accept_own/__init__.py
diff --git a/tests/topotests/bgp_accept_own/ce1/bgpd.conf b/tests/topotests/bgp_accept_own/ce1/bgpd.conf
new file mode 100644
index 000000000..fa53a4291
--- /dev/null
+++ b/tests/topotests/bgp_accept_own/ce1/bgpd.conf
@@ -0,0 +1,12 @@
+!
+debug bgp updates
+!
+router bgp 65010
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.2 remote-as external
+ neighbor 192.168.1.2 timers 1 3
+ neighbor 192.168.1.2 timers connect 1
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_accept_own/ce1/zebra.conf b/tests/topotests/bgp_accept_own/ce1/zebra.conf
new file mode 100644
index 000000000..7863ae165
--- /dev/null
+++ b/tests/topotests/bgp_accept_own/ce1/zebra.conf
@@ -0,0 +1,9 @@
+!
+interface lo
+ ip address 172.16.255.1/32
+!
+interface ce1-eth0
+ ip address 192.168.1.1/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_accept_own/ce2/bgpd.conf b/tests/topotests/bgp_accept_own/ce2/bgpd.conf
new file mode 100644
index 000000000..cdf8898c9
--- /dev/null
+++ b/tests/topotests/bgp_accept_own/ce2/bgpd.conf
@@ -0,0 +1,12 @@
+!
+debug bgp updates
+!
+router bgp 65020
+ no bgp ebgp-requires-policy
+ neighbor 192.168.2.2 remote-as external
+ neighbor 192.168.2.2 timers 1 3
+ neighbor 192.168.2.2 timers connect 1
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_accept_own/ce2/zebra.conf b/tests/topotests/bgp_accept_own/ce2/zebra.conf
new file mode 100644
index 000000000..829967e36
--- /dev/null
+++ b/tests/topotests/bgp_accept_own/ce2/zebra.conf
@@ -0,0 +1,9 @@
+!
+interface lo
+ ip address 172.16.255.2/32
+!
+interface ce2-eth0
+ ip address 192.168.2.1/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_accept_own/pe1/bgpd.conf b/tests/topotests/bgp_accept_own/pe1/bgpd.conf
new file mode 100644
index 000000000..863129373
--- /dev/null
+++ b/tests/topotests/bgp_accept_own/pe1/bgpd.conf
@@ -0,0 +1,49 @@
+!
+debug bgp updates
+debug bgp vpn leak-from-vrf
+debug bgp vpn leak-to-vrf
+debug bgp nht
+!
+router bgp 65001
+ bgp router-id 10.10.10.10
+ no bgp ebgp-requires-policy
+ no bgp default ipv4-unicast
+ neighbor 10.10.10.101 remote-as internal
+ neighbor 10.10.10.101 update-source 10.10.10.10
+ neighbor 10.10.10.101 timers 1 3
+ neighbor 10.10.10.101 timers connect 1
+ address-family ipv4 vpn
+ neighbor 10.10.10.101 activate
+ neighbor 10.10.10.101 attribute-unchanged
+ exit-address-family
+!
+router bgp 65001 vrf Customer
+ bgp router-id 192.168.1.2
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.1 remote-as external
+ neighbor 192.168.1.1 timers 1 3
+ neighbor 192.168.1.1 timers connect 1
+ address-family ipv4 unicast
+ label vpn export 10
+ rd vpn export 192.168.1.2:2
+ rt vpn import 192.168.1.2:2
+ rt vpn export 192.168.1.2:2
+ export vpn
+ import vpn
+ exit-address-family
+!
+router bgp 65001 vrf Service
+ bgp router-id 192.168.2.2
+ no bgp ebgp-requires-policy
+ neighbor 192.168.2.1 remote-as external
+ neighbor 192.168.2.1 timers 1 3
+ neighbor 192.168.2.1 timers connect 1
+ address-family ipv4 unicast
+ label vpn export 20
+ rd vpn export 192.168.2.2:2
+ rt vpn import 192.168.2.2:2
+ rt vpn export 192.168.2.2:2
+ export vpn
+ import vpn
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_accept_own/pe1/ldpd.conf b/tests/topotests/bgp_accept_own/pe1/ldpd.conf
new file mode 100644
index 000000000..7c1ea33a3
--- /dev/null
+++ b/tests/topotests/bgp_accept_own/pe1/ldpd.conf
@@ -0,0 +1,12 @@
+mpls ldp
+ router-id 10.10.10.10
+ !
+ address-family ipv4
+ discovery transport-address 10.10.10.10
+ !
+ interface pe1-eth2
+ exit
+ !
+ exit-address-family
+ !
+exit
diff --git a/tests/topotests/bgp_accept_own/pe1/ospfd.conf b/tests/topotests/bgp_accept_own/pe1/ospfd.conf
new file mode 100644
index 000000000..1a5e1a06b
--- /dev/null
+++ b/tests/topotests/bgp_accept_own/pe1/ospfd.conf
@@ -0,0 +1,7 @@
+interface pe1-eth2
+ ip ospf dead-interval 4
+ ip ospf hello-interval 1
+!
+router ospf
+ router-id 10.10.10.10
+ network 0.0.0.0/0 area 0
diff --git a/tests/topotests/bgp_accept_own/pe1/zebra.conf b/tests/topotests/bgp_accept_own/pe1/zebra.conf
new file mode 100644
index 000000000..71476d2ae
--- /dev/null
+++ b/tests/topotests/bgp_accept_own/pe1/zebra.conf
@@ -0,0 +1,15 @@
+!
+interface lo
+ ip address 10.10.10.10/32
+!
+interface pe1-eth0 vrf Customer
+ ip address 192.168.1.2/24
+!
+interface pe1-eth1 vrf Service
+ ip address 192.168.2.2/24
+!
+interface pe1-eth2
+ ip address 10.0.1.1/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_accept_own/rr1/bgpd.conf b/tests/topotests/bgp_accept_own/rr1/bgpd.conf
new file mode 100644
index 000000000..4f0a6ab0f
--- /dev/null
+++ b/tests/topotests/bgp_accept_own/rr1/bgpd.conf
@@ -0,0 +1,25 @@
+!
+debug bgp updates
+!
+router bgp 65001
+ bgp router-id 10.10.10.101
+ bgp route-reflector allow-outbound-policy
+ no bgp ebgp-requires-policy
+ no bgp default ipv4-unicast
+ neighbor 10.10.10.10 remote-as internal
+ neighbor 10.10.10.10 update-source 10.10.10.101
+ neighbor 10.10.10.10 timers 1 3
+ neighbor 10.10.10.10 timers connect 1
+ address-family ipv4 vpn
+ neighbor 10.10.10.10 activate
+ neighbor 10.10.10.10 route-reflector-client
+ neighbor 10.10.10.10 route-map pe1 out
+ exit-address-family
+!
+route-map pe1 permit 10
+ set extcommunity rt 192.168.1.2:2 192.168.2.2:2
+ set community 65001:111 accept-own additive
+ set ip next-hop unchanged
+route-map pe1 permit 20
+exit
+!
diff --git a/tests/topotests/bgp_accept_own/rr1/ldpd.conf b/tests/topotests/bgp_accept_own/rr1/ldpd.conf
new file mode 100644
index 000000000..036990186
--- /dev/null
+++ b/tests/topotests/bgp_accept_own/rr1/ldpd.conf
@@ -0,0 +1,12 @@
+mpls ldp
+ router-id 10.10.10.101
+ !
+ address-family ipv4
+ discovery transport-address 10.10.10.101
+ !
+ interface rr1-eth0
+ exit
+ !
+ exit-address-family
+ !
+exit
diff --git a/tests/topotests/bgp_accept_own/rr1/ospfd.conf b/tests/topotests/bgp_accept_own/rr1/ospfd.conf
new file mode 100644
index 000000000..b598246ef
--- /dev/null
+++ b/tests/topotests/bgp_accept_own/rr1/ospfd.conf
@@ -0,0 +1,7 @@
+interface rr1-eth0
+ ip ospf dead-interval 4
+ ip ospf hello-interval 1
+!
+router ospf
+ router-id 10.10.10.101
+ network 0.0.0.0/0 area 0
diff --git a/tests/topotests/bgp_accept_own/rr1/zebra.conf b/tests/topotests/bgp_accept_own/rr1/zebra.conf
new file mode 100644
index 000000000..aa3f633bf
--- /dev/null
+++ b/tests/topotests/bgp_accept_own/rr1/zebra.conf
@@ -0,0 +1,9 @@
+!
+interface lo
+ ip address 10.10.10.101/32
+!
+interface rr1-eth0
+ ip address 10.0.1.2/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_accept_own/test_bgp_accept_own.py b/tests/topotests/bgp_accept_own/test_bgp_accept_own.py
new file mode 100644
index 000000000..161530b48
--- /dev/null
+++ b/tests/topotests/bgp_accept_own/test_bgp_accept_own.py
@@ -0,0 +1,198 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2022 by
+# Donatas Abraitis <donatas@opensourcerouting.org>
+#
+# 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.
+#
+
+"""
+
+"""
+
+import os
+import sys
+import json
+import pytest
+import functools
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.common_config import step
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def build_topo(tgen):
+ tgen.add_router("ce1")
+ tgen.add_router("ce2")
+ tgen.add_router("pe1")
+ tgen.add_router("rr1")
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["ce1"])
+ switch.add_link(tgen.gears["pe1"])
+
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["ce2"])
+ switch.add_link(tgen.gears["pe1"])
+
+ switch = tgen.add_switch("s3")
+ switch.add_link(tgen.gears["pe1"])
+ switch.add_link(tgen.gears["rr1"])
+
+
+def setup_module(mod):
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ pe1 = tgen.gears["pe1"]
+ rr1 = tgen.gears["rr1"]
+
+ pe1.run("ip link add Customer type vrf table 1001")
+ pe1.run("ip link set up dev Customer")
+ pe1.run("ip link set pe1-eth0 master Customer")
+ pe1.run("ip link add Service type vrf table 1002")
+ pe1.run("ip link set up dev Service")
+ pe1.run("ip link set pe1-eth1 master Service")
+ pe1.run("sysctl -w net.mpls.conf.pe1-eth2.input=1")
+ rr1.run("sysctl -w net.mpls.conf.rr1-eth0.input=1")
+
+ router_list = tgen.routers()
+
+ for i, (rname, router) in enumerate(router_list.items(), 1):
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_LDP, os.path.join(CWD, "{}/ldpd.conf".format(rname))
+ )
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_accept_own():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ pe1 = tgen.gears["pe1"]
+ ce2 = tgen.gears["ce2"]
+
+ step("Check if routes are not installed in PE1 from RR1 (due to ORIGINATOR_ID)")
+
+ def _bgp_check_received_routes_due_originator_id():
+ output = json.loads(pe1.vtysh_cmd("show bgp ipv4 vpn summary json"))
+ expected = {"peers": {"10.10.10.101": {"pfxRcd": 0, "pfxSnt": 4}}}
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_check_received_routes_due_originator_id)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
+ assert result is None, "Failed, received routes from RR1 regardless ORIGINATOR_ID"
+
+ step("Enable ACCEPT_OWN for RR1")
+
+ pe1.vtysh_cmd(
+ """
+ configure terminal
+ router bgp 65001
+ address-family ipv4 vpn
+ neighbor 10.10.10.101 accept-own
+ """
+ )
+
+ step("Check if we received routes due to ACCEPT_OWN from RR1")
+
+ def _bgp_check_received_routes_with_modified_rts():
+ output = json.loads(pe1.vtysh_cmd("show bgp ipv4 vpn summary json"))
+ expected = {"peers": {"10.10.10.101": {"pfxRcd": 4, "pfxSnt": 4}}}
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_check_received_routes_with_modified_rts)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
+ assert (
+ result is None
+ ), "Failed, didn't receive routes from RR1 with ACCEPT_OWN enabled"
+
+ step(
+ "Check if 172.16.255.1/32 is imported into vrf Service due to modified RT list at RR1"
+ )
+
+ def _bgp_check_received_routes_with_changed_rts():
+ output = json.loads(
+ pe1.vtysh_cmd("show bgp vrf Service ipv4 unicast 172.16.255.1/32 json")
+ )
+ expected = {
+ "paths": [
+ {
+ "community": {
+ "string": "65001:111"
+ },
+ "extendedCommunity": {
+ "string": "RT:192.168.1.2:2 RT:192.168.2.2:2"
+ },
+ }
+ ]
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_check_received_routes_with_changed_rts)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
+ assert (
+ result is None
+ ), "Failed, routes are not imported from RR1 with modified RT list"
+
+ step("Check if 172.16.255.1/32 is announced to CE2")
+
+ def _bgp_check_received_routes_from_pe():
+ output = json.loads(ce2.vtysh_cmd("show ip route 172.16.255.1/32 json"))
+ expected = {
+ "172.16.255.1/32": [
+ {
+ "protocol": "bgp",
+ "installed": True,
+ "nexthops": [{"ip": "192.168.2.2"}],
+ }
+ ]
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_check_received_routes_from_pe)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=1)
+ assert (
+ result is None
+ ), "Failed, didn't receive 172.16.255.1/32 from PE1"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_aigp/__init__.py b/tests/topotests/bgp_aigp/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/bgp_aigp/__init__.py
diff --git a/tests/topotests/bgp_aigp/r1/bgpd.conf b/tests/topotests/bgp_aigp/r1/bgpd.conf
new file mode 100644
index 000000000..74a0215bc
--- /dev/null
+++ b/tests/topotests/bgp_aigp/r1/bgpd.conf
@@ -0,0 +1,12 @@
+router bgp 65001
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 10.0.0.2 remote-as internal
+ neighbor 10.0.0.2 update-source lo
+ neighbor 10.0.0.2 timers 1 3
+ neighbor 10.0.0.2 timers connect 1
+ neighbor 10.0.0.3 remote-as internal
+ neighbor 10.0.0.3 timers 1 3
+ neighbor 10.0.0.3 timers connect 1
+ neighbor 10.0.0.3 update-source lo
+!
diff --git a/tests/topotests/bgp_aigp/r1/ospfd.conf b/tests/topotests/bgp_aigp/r1/ospfd.conf
new file mode 100644
index 000000000..38aa11d03
--- /dev/null
+++ b/tests/topotests/bgp_aigp/r1/ospfd.conf
@@ -0,0 +1,17 @@
+!
+interface lo
+ ip ospf cost 10
+!
+interface r1-eth0
+ ip ospf dead-interval 4
+ ip ospf hello-interval 1
+ ip ospf cost 10
+!
+interface r1-eth1
+ ip ospf dead-interval 4
+ ip ospf hello-interval 1
+ ip ospf cost 30
+!
+router ospf
+ router-id 10.0.0.1
+ network 0.0.0.0/0 area 0
diff --git a/tests/topotests/bgp_aigp/r1/zebra.conf b/tests/topotests/bgp_aigp/r1/zebra.conf
new file mode 100644
index 000000000..0ed22d37b
--- /dev/null
+++ b/tests/topotests/bgp_aigp/r1/zebra.conf
@@ -0,0 +1,10 @@
+!
+interface lo
+ ip address 10.0.0.1/32
+!
+interface r1-eth0
+ ip address 192.168.12.1/24
+!
+interface r1-eth1
+ ip address 192.168.13.1/24
+!
diff --git a/tests/topotests/bgp_aigp/r2/bgpd.conf b/tests/topotests/bgp_aigp/r2/bgpd.conf
new file mode 100644
index 000000000..ae72f215c
--- /dev/null
+++ b/tests/topotests/bgp_aigp/r2/bgpd.conf
@@ -0,0 +1,14 @@
+router bgp 65001
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 10.0.0.1 remote-as internal
+ neighbor 10.0.0.1 timers 1 3
+ neighbor 10.0.0.1 timers connect 1
+ neighbor 192.168.24.4 remote-as external
+ neighbor 192.168.24.4 timers 1 3
+ neighbor 192.168.24.4 timers connect 1
+ neighbor 192.168.24.4 aigp
+ address-family ipv4
+ redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_aigp/r2/ospfd.conf b/tests/topotests/bgp_aigp/r2/ospfd.conf
new file mode 100644
index 000000000..ed31941f6
--- /dev/null
+++ b/tests/topotests/bgp_aigp/r2/ospfd.conf
@@ -0,0 +1,13 @@
+!
+interface lo
+ ip ospf cost 10
+!
+interface r2-eth0
+ ip ospf dead-interval 4
+ ip ospf hello-interval 1
+ ip ospf cost 10
+!
+router ospf
+ router-id 10.0.0.2
+ network 192.168.12.0/24 area 0
+ network 10.0.0.2/32 area 0
diff --git a/tests/topotests/bgp_aigp/r2/zebra.conf b/tests/topotests/bgp_aigp/r2/zebra.conf
new file mode 100644
index 000000000..6d6a557ca
--- /dev/null
+++ b/tests/topotests/bgp_aigp/r2/zebra.conf
@@ -0,0 +1,10 @@
+!
+interface lo
+ ip address 10.0.0.2/32
+!
+interface r2-eth0
+ ip address 192.168.12.2/24
+!
+interface r2-eth1
+ ip address 192.168.24.2/24
+!
diff --git a/tests/topotests/bgp_aigp/r3/bgpd.conf b/tests/topotests/bgp_aigp/r3/bgpd.conf
new file mode 100644
index 000000000..7572e268c
--- /dev/null
+++ b/tests/topotests/bgp_aigp/r3/bgpd.conf
@@ -0,0 +1,14 @@
+router bgp 65001
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 10.0.0.1 remote-as internal
+ neighbor 10.0.0.1 timers 1 3
+ neighbor 10.0.0.1 timers connect 1
+ neighbor 192.168.35.5 remote-as external
+ neighbor 192.168.35.5 timers 1 3
+ neighbor 192.168.35.5 timers connect 1
+ neighbor 192.168.35.5 aigp
+ address-family ipv4
+ redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_aigp/r3/ospfd.conf b/tests/topotests/bgp_aigp/r3/ospfd.conf
new file mode 100644
index 000000000..f971ad6f8
--- /dev/null
+++ b/tests/topotests/bgp_aigp/r3/ospfd.conf
@@ -0,0 +1,13 @@
+!
+interface lo
+ ip ospf cost 10
+!
+interface r3-eth0
+ ip ospf dead-interval 4
+ ip ospf hello-interval 1
+ ip ospf cost 30
+!
+router ospf
+ router-id 10.0.0.3
+ network 192.168.13.0/24 area 0
+ network 10.0.0.3/32 area 0
diff --git a/tests/topotests/bgp_aigp/r3/zebra.conf b/tests/topotests/bgp_aigp/r3/zebra.conf
new file mode 100644
index 000000000..82c87d550
--- /dev/null
+++ b/tests/topotests/bgp_aigp/r3/zebra.conf
@@ -0,0 +1,10 @@
+!
+interface lo
+ ip address 10.0.0.3/32
+!
+interface r3-eth0
+ ip address 192.168.13.3/24
+!
+interface r3-eth1
+ ip address 192.168.35.3/24
+!
diff --git a/tests/topotests/bgp_aigp/r4/bgpd.conf b/tests/topotests/bgp_aigp/r4/bgpd.conf
new file mode 100644
index 000000000..d2b96b7b0
--- /dev/null
+++ b/tests/topotests/bgp_aigp/r4/bgpd.conf
@@ -0,0 +1,16 @@
+router bgp 65002
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 192.168.24.2 remote-as external
+ neighbor 192.168.24.2 timers 1 3
+ neighbor 192.168.24.2 timers connect 1
+ neighbor 192.168.24.2 aigp
+ neighbor 10.0.0.6 remote-as internal
+ neighbor 10.0.0.6 timers 1 3
+ neighbor 10.0.0.6 timers connect 1
+ neighbor 10.0.0.6 update-source lo
+ address-family ipv4
+ redistribute connected
+ redistribute ospf
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_aigp/r4/ospfd.conf b/tests/topotests/bgp_aigp/r4/ospfd.conf
new file mode 100644
index 000000000..c9e6796f6
--- /dev/null
+++ b/tests/topotests/bgp_aigp/r4/ospfd.conf
@@ -0,0 +1,13 @@
+!
+interface lo
+ ip ospf cost 10
+!
+interface r4-eth1
+ ip ospf dead-interval 4
+ ip ospf hello-interval 1
+ ip ospf cost 20
+!
+router ospf
+ router-id 10.0.0.4
+ network 192.168.46.0/24 area 0
+ network 10.0.0.4/32 area 0
diff --git a/tests/topotests/bgp_aigp/r4/zebra.conf b/tests/topotests/bgp_aigp/r4/zebra.conf
new file mode 100644
index 000000000..5f544e855
--- /dev/null
+++ b/tests/topotests/bgp_aigp/r4/zebra.conf
@@ -0,0 +1,10 @@
+!
+interface lo
+ ip address 10.0.0.4/32
+!
+interface r4-eth0
+ ip address 192.168.24.4/24
+!
+interface r4-eth1
+ ip address 192.168.46.4/24
+!
diff --git a/tests/topotests/bgp_aigp/r5/bgpd.conf b/tests/topotests/bgp_aigp/r5/bgpd.conf
new file mode 100644
index 000000000..944872289
--- /dev/null
+++ b/tests/topotests/bgp_aigp/r5/bgpd.conf
@@ -0,0 +1,16 @@
+router bgp 65002
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 192.168.35.3 remote-as external
+ neighbor 192.168.35.3 timers 1 3
+ neighbor 192.168.35.3 timers connect 1
+ neighbor 192.168.35.3 aigp
+ neighbor 10.0.0.6 remote-as internal
+ neighbor 10.0.0.6 timers 1 3
+ neighbor 10.0.0.6 timers connect 1
+ neighbor 10.0.0.6 update-source lo
+ address-family ipv4
+ redistribute connected
+ redistribute ospf
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_aigp/r5/ospfd.conf b/tests/topotests/bgp_aigp/r5/ospfd.conf
new file mode 100644
index 000000000..b853c7410
--- /dev/null
+++ b/tests/topotests/bgp_aigp/r5/ospfd.conf
@@ -0,0 +1,13 @@
+!
+interface lo
+ ip ospf cost 10
+!
+interface r5-eth1
+ ip ospf dead-interval 4
+ ip ospf hello-interval 1
+ ip ospf cost 10
+!
+router ospf
+ router-id 10.0.0.5
+ network 192.168.56.0/24 area 0
+ network 10.0.0.5/32 area 0
diff --git a/tests/topotests/bgp_aigp/r5/zebra.conf b/tests/topotests/bgp_aigp/r5/zebra.conf
new file mode 100644
index 000000000..69b8bf2c3
--- /dev/null
+++ b/tests/topotests/bgp_aigp/r5/zebra.conf
@@ -0,0 +1,10 @@
+!
+interface lo
+ ip address 10.0.0.5/32
+!
+interface r5-eth0
+ ip address 192.168.35.5/24
+!
+interface r5-eth1
+ ip address 192.168.56.5/24
+!
diff --git a/tests/topotests/bgp_aigp/r6/bgpd.conf b/tests/topotests/bgp_aigp/r6/bgpd.conf
new file mode 100644
index 000000000..15d9437a8
--- /dev/null
+++ b/tests/topotests/bgp_aigp/r6/bgpd.conf
@@ -0,0 +1,20 @@
+router bgp 65002
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 10.0.0.4 remote-as internal
+ neighbor 10.0.0.4 timers 1 3
+ neighbor 10.0.0.4 timers connect 1
+ neighbor 10.0.0.4 route-reflector-client
+ neighbor 10.0.0.4 update-source lo
+ neighbor 10.0.0.5 remote-as internal
+ neighbor 10.0.0.5 timers 1 3
+ neighbor 10.0.0.5 timers connect 1
+ neighbor 10.0.0.5 route-reflector-client
+ neighbor 10.0.0.5 update-source lo
+ neighbor 192.168.67.7 remote-as internal
+ neighbor 192.168.67.7 timers 1 3
+ neighbor 192.168.67.7 timers connect 1
+ address-family ipv4
+ redistribute ospf
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_aigp/r6/ospfd.conf b/tests/topotests/bgp_aigp/r6/ospfd.conf
new file mode 100644
index 000000000..46b293317
--- /dev/null
+++ b/tests/topotests/bgp_aigp/r6/ospfd.conf
@@ -0,0 +1,17 @@
+!
+interface lo
+ ip ospf cost 10
+!
+interface r6-eth0
+ ip ospf dead-interval 4
+ ip ospf hello-interval 1
+ ip ospf cost 20
+!
+interface r6-eth1
+ ip ospf dead-interval 4
+ ip ospf hello-interval 1
+ ip ospf cost 10
+!
+router ospf
+ router-id 10.0.0.6
+ network 0.0.0.0/0 area 0
diff --git a/tests/topotests/bgp_aigp/r6/zebra.conf b/tests/topotests/bgp_aigp/r6/zebra.conf
new file mode 100644
index 000000000..f8ca5f8b8
--- /dev/null
+++ b/tests/topotests/bgp_aigp/r6/zebra.conf
@@ -0,0 +1,13 @@
+!
+interface lo
+ ip address 10.0.0.6/32
+!
+interface r6-eth0
+ ip address 192.168.46.6/24
+!
+interface r6-eth1
+ ip address 192.168.56.6/24
+!
+interface r6-eth2
+ ip address 192.168.67.6/24
+!
diff --git a/tests/topotests/bgp_aigp/r7/bgpd.conf b/tests/topotests/bgp_aigp/r7/bgpd.conf
new file mode 100644
index 000000000..00d85cfad
--- /dev/null
+++ b/tests/topotests/bgp_aigp/r7/bgpd.conf
@@ -0,0 +1,22 @@
+router bgp 65002
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 192.168.67.6 remote-as internal
+ neighbor 192.168.67.6 timers 1 3
+ neighbor 192.168.67.6 timers connect 1
+ address-family ipv4
+ redistribute connected route-map rmap metric 71
+ exit-address-family
+!
+ip prefix-list p71 seq 5 permit 10.0.0.71/32
+ip prefix-list p72 seq 5 permit 10.0.0.72/32
+!
+route-map rmap permit 10
+ match ip address prefix-list p71
+ set aigp igp-metric
+!
+route-map rmap permit 20
+ match ip address prefix-list p72
+ set aigp 72
+exit
+!
diff --git a/tests/topotests/bgp_aigp/r7/zebra.conf b/tests/topotests/bgp_aigp/r7/zebra.conf
new file mode 100644
index 000000000..4c05df84f
--- /dev/null
+++ b/tests/topotests/bgp_aigp/r7/zebra.conf
@@ -0,0 +1,9 @@
+!
+interface lo
+ ip address 10.0.0.7/32
+ ip address 10.0.0.71/32
+ ip address 10.0.0.72/32
+!
+interface r7-eth0
+ ip address 192.168.67.7/24
+!
diff --git a/tests/topotests/bgp_aigp/test_bgp_aigp.py b/tests/topotests/bgp_aigp/test_bgp_aigp.py
new file mode 100644
index 000000000..9fa80c6da
--- /dev/null
+++ b/tests/topotests/bgp_aigp/test_bgp_aigp.py
@@ -0,0 +1,224 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2022 by
+# Donatas Abraitis <donatas@opensourcerouting.org>
+#
+# 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.
+#
+
+"""
+r7 sets aigp-metric for 10.0.0.71/32 to 71, and 72 for 10.0.0.72/32.
+
+r6 receives those routes with aigp-metric TLV.
+
+r2 and r3 receives those routes with aigp-metric TLV increased by 20,
+and 30 appropriately.
+
+r1 receives routes with aigp-metric TLV 91,101 and 92,102 appropriately.
+"""
+
+import os
+import sys
+import json
+import pytest
+import functools
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.common_config import step
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def build_topo(tgen):
+ for routern in range(1, 8):
+ tgen.add_router("r{}".format(routern))
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r3"])
+
+ switch = tgen.add_switch("s3")
+ switch.add_link(tgen.gears["r2"])
+ switch.add_link(tgen.gears["r4"])
+
+ switch = tgen.add_switch("s4")
+ switch.add_link(tgen.gears["r3"])
+ switch.add_link(tgen.gears["r5"])
+
+ switch = tgen.add_switch("s5")
+ switch.add_link(tgen.gears["r4"])
+ switch.add_link(tgen.gears["r6"])
+
+ switch = tgen.add_switch("s6")
+ switch.add_link(tgen.gears["r5"])
+ switch.add_link(tgen.gears["r6"])
+
+ switch = tgen.add_switch("s7")
+ switch.add_link(tgen.gears["r6"])
+ switch.add_link(tgen.gears["r7"])
+
+
+def setup_module(mod):
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for i, (rname, router) in enumerate(router_list.items(), 1):
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_OSPF, os.path.join(CWD, "{}/ospfd.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_aigp():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+ r2 = tgen.gears["r2"]
+ r3 = tgen.gears["r3"]
+ r4 = tgen.gears["r4"]
+ r5 = tgen.gears["r5"]
+
+ def _bgp_converge():
+ output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 10.0.0.71/32 json"))
+ expected = {
+ "paths": [
+ {
+ "aigpMetric": 101,
+ "valid": True,
+ "bestpath": {"selectionReason": "Router ID"},
+ "nexthops": [{"hostname": "r2", "accessible": True}],
+ },
+ {
+ "aigpMetric": 91,
+ "valid": True,
+ "nexthops": [{"hostname": "r3", "accessible": True}],
+ },
+ ]
+ }
+ return topotest.json_cmp(output, expected)
+
+ def _bgp_check_aigp_metric(router, prefix, aigp):
+ output = json.loads(
+ router.vtysh_cmd("show bgp ipv4 unicast {} json".format(prefix))
+ )
+ expected = {"paths": [{"aigpMetric": aigp, "valid": True}]}
+ return topotest.json_cmp(output, expected)
+
+ def _bgp_check_aigp_metric_bestpath():
+ output = json.loads(
+ r1.vtysh_cmd(
+ "show bgp ipv4 unicast 10.0.0.64/28 longer-prefixes json detail"
+ )
+ )
+ expected = {
+ "routes": {
+ "10.0.0.71/32": [
+ {
+ "aigpMetric": 101,
+ "valid": True,
+ },
+ {
+ "aigpMetric": 91,
+ "valid": True,
+ "bestpath": {"selectionReason": "AIGP"},
+ "nexthops": [{"hostname": "r3", "accessible": True}],
+ },
+ ],
+ "10.0.0.72/32": [
+ {
+ "aigpMetric": 102,
+ "valid": True,
+ },
+ {
+ "aigpMetric": 92,
+ "valid": True,
+ "bestpath": {"selectionReason": "AIGP"},
+ "nexthops": [{"hostname": "r3", "accessible": True}],
+ },
+ ],
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ # Initial converge, AIGP is not involved in best-path selection process
+ test_func = functools.partial(_bgp_converge)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "can't converge initially"
+
+ # Enable `bgp bestpath aigp`
+ r1.vtysh_cmd(
+ """
+ configure terminal
+ router bgp
+ bgp bestpath aigp
+ """
+ )
+
+ # r4, 10.0.0.71/32 with aigp-metric 71
+ test_func = functools.partial(_bgp_check_aigp_metric, r4, "10.0.0.71/32", 71)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "aigp-metric for 10.0.0.71/32 is not 71"
+
+ # r5, 10.0.0.72/32 with aigp-metric 72
+ test_func = functools.partial(_bgp_check_aigp_metric, r5, "10.0.0.72/32", 72)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "aigp-metric for 10.0.0.72/32 is not 72"
+
+ # r2, 10.0.0.71/32 with aigp-metric 101 (71 + 30)
+ test_func = functools.partial(_bgp_check_aigp_metric, r2, "10.0.0.71/32", 101)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "aigp-metric for 10.0.0.71/32 is not 101"
+
+ # r3, 10.0.0.72/32 with aigp-metric 92 (72 + 20)
+ test_func = functools.partial(_bgp_check_aigp_metric, r3, "10.0.0.72/32", 92)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "aigp-metric for 10.0.0.72/32 is not 92"
+
+ # r1, check if AIGP is considered in best-path selection (lowest wins)
+ test_func = functools.partial(_bgp_check_aigp_metric_bestpath)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "AIGP attribute is not considered in best-path selection"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_basic_functionality_topo1/test_bgp_basic_functionality.py b/tests/topotests/bgp_basic_functionality_topo1/test_bgp_basic_functionality.py
index b18e32f6b..42b9b8adb 100644
--- a/tests/topotests/bgp_basic_functionality_topo1/test_bgp_basic_functionality.py
+++ b/tests/topotests/bgp_basic_functionality_topo1/test_bgp_basic_functionality.py
@@ -121,7 +121,7 @@ def setup_module(mod):
# Required linux kernel version for this suite to run.
result = required_linux_kernel_version("4.15")
if result is not True:
- pytest.skip("Kernel requirements are not met")
+ pytest.skip("Kernel requirements are not met, kernel version should be >=4.15")
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
@@ -1148,9 +1148,9 @@ def test_bgp_with_loopback_with_same_subnet_p1(request):
tgen, addr_type, dut, input_dict_r1, expected=False
) # pylint: disable=E1123
assert result is not True, (
- "Testcase {} : Failed \n".format(tc_name)
- + "Expected behavior: routes should not present in fib \n"
- + "Error: {}".format(result)
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
step("Verify Ipv4 and Ipv6 network installed in r3 RIB but not in FIB")
@@ -1169,9 +1169,9 @@ def test_bgp_with_loopback_with_same_subnet_p1(request):
tgen, addr_type, dut, input_dict_r1, expected=False
) # pylint: disable=E1123
assert result is not True, (
- "Testcase {} : Failed \n".format(tc_name)
- + "Expected behavior: routes should not present in fib \n"
- + "Error: {}".format(result)
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
write_test_footer(tc_name)
diff --git a/tests/topotests/bgp_communities_topo1/test_bgp_communities.py b/tests/topotests/bgp_communities_topo1/test_bgp_communities.py
index e4c25ff5c..1c1a5cdfe 100644
--- a/tests/topotests/bgp_communities_topo1/test_bgp_communities.py
+++ b/tests/topotests/bgp_communities_topo1/test_bgp_communities.py
@@ -83,7 +83,7 @@ def setup_module(mod):
# Required linux kernel version for this suite to run.
result = required_linux_kernel_version("4.15")
if result is not True:
- pytest.skip("Kernel requirements are not met")
+ pytest.skip("Kernel requirements are not met, kernel version should be >= 4.15")
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
@@ -317,17 +317,18 @@ def test_bgp_no_advertise_community_p0(request):
)
result = verify_bgp_rib(tgen, addr_type, dut, input_dict, expected=False)
- assert result is not True, "Testcase {} : Failed \n ".format(
- tc_name
- ) + " Routes still present in R3 router. Error: {}".format(result)
+ assert result is not True, (
+ "Testcase {} : Failed \n Expected: "
+ "Routes still present in {} router. Found: {}".format(tc_name, dut, result)
+ )
result = verify_rib(
tgen, addr_type, dut, input_dict, protocol=protocol, expected=False
)
assert (
result is not True
- ), "Testcase {} : Failed \n Routes still present in R3 router. Error: {}".format(
- tc_name, result
+ ), "Testcase {} : Failed \n Expected: Routes still present in {} router. Found: {}".format(
+ tc_name, dut, result
)
step("Remove and Add no advertise community")
diff --git a/tests/topotests/bgp_communities_topo1/test_bgp_communities_topo2.py b/tests/topotests/bgp_communities_topo1/test_bgp_communities_topo2.py
index f6ee9ea79..a93061740 100644
--- a/tests/topotests/bgp_communities_topo1/test_bgp_communities_topo2.py
+++ b/tests/topotests/bgp_communities_topo1/test_bgp_communities_topo2.py
@@ -87,7 +87,7 @@ def setup_module(mod):
# Required linux kernel version for this suite to run.
result = required_linux_kernel_version("4.14")
if result is not True:
- pytest.skip("Kernel requirements are not met")
+ pytest.skip("Kernel requirements are not met, kernel version should be >= 4.14")
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
@@ -305,8 +305,10 @@ def test_bgp_no_export_local_as_and_internet_communities_p0(request):
],
expected=False,
)
- assert result is not True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes are still present in rib of r3 \n "
+ "Found: {}".format(tc_name, result)
)
step("Remove route-map from redistribute static on R1")
diff --git a/tests/topotests/bgp_conditional_advertisement_track_peer/__init__.py b/tests/topotests/bgp_conditional_advertisement_track_peer/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/bgp_conditional_advertisement_track_peer/__init__.py
diff --git a/tests/topotests/bgp_conditional_advertisement_track_peer/r1/bgpd.conf b/tests/topotests/bgp_conditional_advertisement_track_peer/r1/bgpd.conf
new file mode 100644
index 000000000..1e98f4e49
--- /dev/null
+++ b/tests/topotests/bgp_conditional_advertisement_track_peer/r1/bgpd.conf
@@ -0,0 +1,17 @@
+!
+router bgp 65001
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.2 remote-as external
+ neighbor 192.168.1.2 timers 3 10
+ address-family ipv4 unicast
+ neighbor 192.168.1.2 route-map r2 in
+ exit-address-family
+!
+ip prefix-list p1 seq 5 permit 172.16.255.31/32
+!
+route-map r2 permit 10
+ match ip address prefix-list p1
+ set as-path replace 65003
+route-map r2 permit 20
+ set as-path replace any
+!
diff --git a/tests/topotests/bgp_conditional_advertisement_track_peer/r1/zebra.conf b/tests/topotests/bgp_conditional_advertisement_track_peer/r1/zebra.conf
new file mode 100644
index 000000000..acf120b20
--- /dev/null
+++ b/tests/topotests/bgp_conditional_advertisement_track_peer/r1/zebra.conf
@@ -0,0 +1,6 @@
+!
+interface r1-eth0
+ ip address 192.168.1.1/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_conditional_advertisement_track_peer/r2/bgpd.conf b/tests/topotests/bgp_conditional_advertisement_track_peer/r2/bgpd.conf
new file mode 100644
index 000000000..66c3dc53b
--- /dev/null
+++ b/tests/topotests/bgp_conditional_advertisement_track_peer/r2/bgpd.conf
@@ -0,0 +1,28 @@
+!
+router bgp 65002
+ no bgp ebgp-requires-policy
+ bgp conditional-advertisement timer 5
+ neighbor 192.168.1.1 remote-as external
+ neighbor 192.168.1.1 timers 3 10
+ neighbor 192.168.2.1 remote-as external
+ neighbor 192.168.2.1 timers 3 10
+ address-family ipv4 unicast
+ redistribute static
+ neighbor 192.168.1.1 advertise-map advertise exist-map exist
+ neighbor 192.168.1.1 route-map deny-all out
+ neighbor 192.168.2.1 route-map exist in
+ exit-address-family
+!
+ip prefix-list exist seq 5 permit 172.16.255.3/32
+ip prefix-list advertise seq 5 permit 172.16.255.2/32
+!
+route-map advertise permit 10
+ match ip address prefix-list advertise
+exit
+!
+route-map exist permit 10
+ match ip address prefix-list exist
+exit
+!
+route-map deny-all deny 10
+exit
diff --git a/tests/topotests/bgp_conditional_advertisement_track_peer/r2/staticd.conf b/tests/topotests/bgp_conditional_advertisement_track_peer/r2/staticd.conf
new file mode 100644
index 000000000..6c013e275
--- /dev/null
+++ b/tests/topotests/bgp_conditional_advertisement_track_peer/r2/staticd.conf
@@ -0,0 +1,3 @@
+!
+ip route 172.16.255.2/32 r2-eth1
+!
diff --git a/tests/topotests/bgp_conditional_advertisement_track_peer/r2/zebra.conf b/tests/topotests/bgp_conditional_advertisement_track_peer/r2/zebra.conf
new file mode 100644
index 000000000..f22995434
--- /dev/null
+++ b/tests/topotests/bgp_conditional_advertisement_track_peer/r2/zebra.conf
@@ -0,0 +1,9 @@
+!
+interface r2-eth0
+ ip address 192.168.1.2/24
+!
+interface r2-eth1
+ ip address 192.168.2.2/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_conditional_advertisement_track_peer/r3/bgpd.conf b/tests/topotests/bgp_conditional_advertisement_track_peer/r3/bgpd.conf
new file mode 100644
index 000000000..5058d405d
--- /dev/null
+++ b/tests/topotests/bgp_conditional_advertisement_track_peer/r3/bgpd.conf
@@ -0,0 +1,10 @@
+!
+router bgp 65003
+ no bgp ebgp-requires-policy
+ neighbor 192.168.2.2 remote-as external
+ neighbor 192.168.2.2 timers 3 10
+ neighbor 192.168.2.2 shutdown
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_conditional_advertisement_track_peer/r3/zebra.conf b/tests/topotests/bgp_conditional_advertisement_track_peer/r3/zebra.conf
new file mode 100644
index 000000000..268163e0e
--- /dev/null
+++ b/tests/topotests/bgp_conditional_advertisement_track_peer/r3/zebra.conf
@@ -0,0 +1,9 @@
+!
+int lo
+ ip address 172.16.255.3/32
+!
+interface r3-eth0
+ ip address 192.168.2.1/24
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_conditional_advertisement_track_peer/test_bgp_conditional_advertisement_track_peer.py b/tests/topotests/bgp_conditional_advertisement_track_peer/test_bgp_conditional_advertisement_track_peer.py
new file mode 100644
index 000000000..591bac168
--- /dev/null
+++ b/tests/topotests/bgp_conditional_advertisement_track_peer/test_bgp_conditional_advertisement_track_peer.py
@@ -0,0 +1,154 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2022 by
+# Donatas Abraitis <donatas@opensourcerouting.org>
+#
+# 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.
+#
+
+"""
+Conditionally advertise 172.16.255.2/32 to r1, only if 172.16.255.3/32
+is received from r3.
+
+Also, withdraw if 172.16.255.3/32 disappears.
+"""
+
+import os
+import sys
+import json
+import pytest
+import functools
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.common_config import (
+ step,
+)
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def build_topo(tgen):
+ for routern in range(1, 5):
+ tgen.add_router("r{}".format(routern))
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["r2"])
+ switch.add_link(tgen.gears["r3"])
+
+
+def setup_module(mod):
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for i, (rname, router) in enumerate(router_list.items(), 1):
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_STATIC, os.path.join(CWD, "{}/staticd.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_conditional_advertisement_track_peer():
+ tgen = get_topogen()
+
+ r1 = tgen.gears["r1"]
+ r2 = tgen.gears["r2"]
+ r3 = tgen.gears["r3"]
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ def _bgp_converge():
+ output = json.loads(
+ r2.vtysh_cmd(
+ "show bgp ipv4 unicast neighbors 192.168.1.1 advertised-routes json"
+ )
+ )
+ expected = {
+ "advertisedRoutes": {"172.16.255.2/32": None},
+ "totalPrefixCounter": 0,
+ "filteredPrefixCounter": 0,
+ }
+ return topotest.json_cmp(output, expected)
+
+ # Verify if R2 does not send any routes to R1
+ test_func = functools.partial(_bgp_converge)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
+ assert result is None, "R2 SHOULD not send any routes to R1"
+
+ step("Enable session between R2 and R3")
+ r3.vtysh_cmd(
+ """
+ configure terminal
+ router bgp
+ no neighbor 192.168.2.2 shutdown
+ """
+ )
+
+ def _bgp_check_conditional_static_routes_from_r2():
+ output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast json"))
+ expected = {
+ "routes": {
+ "172.16.255.2/32": [{"valid": True, "nexthops": [{"hostname": "r2"}]}]
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ # Verify if R1 received 172.16.255.2/32 from R2
+ test_func = functools.partial(_bgp_check_conditional_static_routes_from_r2)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
+ assert result is None, "R1 SHOULD receive 172.16.255.2/32 from R2"
+
+ step("Disable session between R2 and R3 again")
+ r3.vtysh_cmd(
+ """
+ configure terminal
+ router bgp
+ neighbor 192.168.2.2 shutdown
+ """
+ )
+
+ # Verify if R2 is not sending any routes to R1 again
+ test_func = functools.partial(_bgp_converge)
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
+ assert result is None, "R2 SHOULD not send any routes to R1"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
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 2784e956f..8fd0120dd 100644
--- a/tests/topotests/bgp_ecmp_topo2/test_ebgp_ecmp_topo2.py
+++ b/tests/topotests/bgp_ecmp_topo2/test_ebgp_ecmp_topo2.py
@@ -90,7 +90,7 @@ def setup_module(mod):
# Required linux kernel version for this suite to run.
result = required_linux_kernel_version("4.15")
if result is not True:
- pytest.skip("Kernel requirements are not met")
+ pytest.skip("Kernel requirements are not met, kernel version should be >=4.15")
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
@@ -436,7 +436,9 @@ def test_ecmp_remove_redistribute_static(request):
)
assert (
result is not True
- ), "Testcase {} : Failed \n Routes still" " present in RIB".format(tc_name)
+ ), "Testcase {} : Failed \n Expected: Routes still present in {} RIB. Found: {}".format(
+ tc_name, dut, result
+ )
logger.info("Enable redistribute static")
input_dict_2 = {
@@ -621,7 +623,9 @@ def test_ecmp_remove_static_route(request):
)
assert (
result is not True
- ), "Testcase {} : Failed \n Routes still" " present in RIB".format(tc_name)
+ ), "Testcase {} : Failed \n Expected: Routes still present in {} RIB. Found: {}".format(
+ tc_name, dut, result
+ )
for addr_type in ADDR_TYPES:
# Enable static routes
@@ -727,7 +731,9 @@ def test_ecmp_remove_nw_advertise(request):
)
assert (
result is not True
- ), "Testcase {} : Failed \n Routes still" " present in RIB".format(tc_name)
+ ), "Testcase {} : Failed \n Expected: Routes still present in {} RIB. Found: {}".format(
+ tc_name, dut, result
+ )
static_or_nw(tgen, topo, tc_name, "advertise_nw", "r2")
for addr_type in ADDR_TYPES:
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 704e8fdf0..185a08683 100644
--- a/tests/topotests/bgp_ecmp_topo2/test_ibgp_ecmp_topo2.py
+++ b/tests/topotests/bgp_ecmp_topo2/test_ibgp_ecmp_topo2.py
@@ -90,7 +90,7 @@ def setup_module(mod):
# Required linux kernel version for this suite to run.
result = required_linux_kernel_version("4.15")
if result is not True:
- pytest.skip("Kernel requirements are not met")
+ pytest.skip("Kernel requirements are not met, kernel version should be >=4.15")
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
@@ -437,7 +437,9 @@ def test_ecmp_remove_redistribute_static(request):
)
assert (
result is not True
- ), "Testcase {} : Failed \n Routes still" " present in RIB".format(tc_name)
+ ), "Testcase {} : Failed \n Expected: Routes still present in {} RIB. Found: {}".format(
+ tc_name, dut, result
+ )
logger.info("Enable redistribute static")
input_dict_2 = {
@@ -622,7 +624,9 @@ def test_ecmp_remove_static_route(request):
)
assert (
result is not True
- ), "Testcase {} : Failed \n Routes still" " present in RIB".format(tc_name)
+ ), "Testcase {} : Failed \n Expected: Routes still present in {} RIB. Found: {}".format(
+ tc_name, dut, result
+ )
for addr_type in ADDR_TYPES:
# Enable static routes
@@ -730,7 +734,9 @@ def test_ecmp_remove_nw_advertise(request):
)
assert (
result is not True
- ), "Testcase {} : Failed \n Routes still" " present in RIB".format(tc_name)
+ ), "Testcase {} : Failed \n Expected: Routes still present in {} RIB. Found: {}".format(
+ tc_name, dut, result
+ )
static_or_nw(tgen, topo, tc_name, "advertise_nw", "r2")
for addr_type in ADDR_TYPES:
diff --git a/tests/topotests/bgp_ecmp_topo3/test_ibgp_ecmp_topo3.py b/tests/topotests/bgp_ecmp_topo3/test_ibgp_ecmp_topo3.py
index 2a51dc83e..9b6480c0d 100644
--- a/tests/topotests/bgp_ecmp_topo3/test_ibgp_ecmp_topo3.py
+++ b/tests/topotests/bgp_ecmp_topo3/test_ibgp_ecmp_topo3.py
@@ -240,17 +240,18 @@ def test_ecmp_fast_convergence(request, test_type, tgen, topo):
logger.info("Ensure BGP has processed the cli")
r2 = tgen.gears["r2"]
output = r2.vtysh_cmd("show run")
- verify = re.search(r"fast-convergence", output )
- assert verify is not None, (
- "r2 does not have the fast convergence command yet")
+ verify = re.search(r"fast-convergence", output)
+ assert verify is not None, "r2 does not have the fast convergence command yet"
logger.info("Shutdown one link b/w r2 and r3")
shutdown_bringup_interface(tgen, "r2", intf1, False)
logger.info("Verify bgp neighbors goes down immediately")
result = verify_bgp_convergence(tgen, topo, dut="r2", expected=False)
- assert result is not True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: BGP should not be converged for {} \n "
+ "Found: {}".format(tc_name, "r2", result)
)
logger.info("Shutdown second link b/w r2 and r3")
@@ -258,8 +259,10 @@ def test_ecmp_fast_convergence(request, test_type, tgen, topo):
logger.info("Verify bgp neighbors goes down immediately")
result = verify_bgp_convergence(tgen, topo, dut="r2", expected=False)
- assert result is not True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: BGP should not be converged for {} \n "
+ "Found: {}".format(tc_name, "r2", result)
)
write_test_footer(tc_name)
diff --git a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-1.py b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-1.py
index f15532550..deca4bcfd 100644
--- a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-1.py
+++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-1.py
@@ -160,7 +160,7 @@ def setup_module(mod):
# Required linux kernel version for this suite to run.
result = required_linux_kernel_version("4.16")
if result is not True:
- pytest.skip("Kernel requirements are not met")
+ pytest.skip("Kernel requirements are not met, kernel version should be >=4.16")
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
@@ -1033,11 +1033,9 @@ def test_BGP_GR_TC_4_p0(request):
)
assert result is not True, (
"Testcase {} : Failed \n "
- "r1: routes are still present in BGP RIB\n Error: {}".format(
- tc_name, result
- )
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
# Verifying RIB routes
result = verify_rib(
@@ -1045,9 +1043,9 @@ def test_BGP_GR_TC_4_p0(request):
)
assert result is not True, (
"Testcase {} : Failed \n "
- "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result)
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
logger.info("[Phase 5] : R2 is about to come up now ")
start_router_daemons(tgen, "r2", ["bgpd"])
@@ -1506,10 +1504,10 @@ def test_BGP_GR_TC_6_1_2_p1(request):
result = verify_r_bit(
tgen, topo, addr_type, input_dict, dut="r2", peer="r1", expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n " "r2: R-bit is set to True\n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: R-bit should not be set to True in r2\n"
+ "Found: {}".format(tc_name, result)
)
logger.info("Restart BGPd on R2 ")
@@ -1528,10 +1526,10 @@ def test_BGP_GR_TC_6_1_2_p1(request):
result = verify_r_bit(
tgen, topo, addr_type, input_dict, dut="r2", peer="r1", expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n " "r2: R-bit is set to True\n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: R-bit should not be set to True in r2\n"
+ "Found: {}".format(tc_name, result)
)
write_test_footer(tc_name)
diff --git a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-2.py b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-2.py
index dda3bd4b3..a92fde2d0 100644
--- a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-2.py
+++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-2.py
@@ -160,7 +160,7 @@ def setup_module(mod):
# Required linux kernel version for this suite to run.
result = required_linux_kernel_version("4.16")
if result is not True:
- pytest.skip("Kernel requirements are not met")
+ pytest.skip("Kernel requirements are not met, kernel version should be >=4.16")
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
diff --git a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-3.py b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-3.py
index e4b533b29..b0166033d 100644
--- a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-3.py
+++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-3.py
@@ -160,7 +160,7 @@ def setup_module(mod):
# Required linux kernel version for this suite to run.
result = required_linux_kernel_version("4.16")
if result is not True:
- pytest.skip("Kernel requirements are not met")
+ pytest.skip("Kernel requirements are not met, kernel version should be >=4.16")
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
@@ -829,11 +829,9 @@ def test_BGP_GR_TC_20_p1(request):
)
assert result is not True, (
"Testcase {} : Failed \n "
- "r1: routes are still present in BGP RIB\n Error: {}".format(
- tc_name, result
- )
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
# Verifying RIB routes
result = verify_rib(
@@ -841,9 +839,9 @@ def test_BGP_GR_TC_20_p1(request):
)
assert result is not True, (
"Testcase {} : Failed \n "
- "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result)
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
logger.info("[Phase 5] : R2 is about to come up now ")
@@ -1117,7 +1115,8 @@ def test_BGP_GR_TC_31_1_p1(request):
)
assert result is not True, (
"Testcase {} : Failed \n "
- "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result)
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
logger.info("[Phase 4] : R1 is about to come up now ")
@@ -1599,11 +1598,9 @@ def test_BGP_GR_TC_9_p1(request):
)
assert result is not True, (
"Testcase {} : Failed \n "
- "r1: routes are still present in BGP RIB\n Error: {}".format(
- tc_name, result
- )
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
# Verifying RIB routes
protocol = "bgp"
@@ -1612,9 +1609,9 @@ def test_BGP_GR_TC_9_p1(request):
)
assert result is not True, (
"Testcase {} : Failed \n "
- "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result)
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
logger.info("[Phase 5] : R2 is about to come up now ")
start_router_daemons(tgen, "r2", ["bgpd"])
@@ -1643,10 +1640,10 @@ def test_BGP_GR_TC_9_p1(request):
result = verify_f_bit(
tgen, topo, addr_type, input_dict, dut="r1", peer="r2", expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n " "r1: F-bit is set to True\n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: F-bit should not be set to True in r1\n"
+ "Found: {}".format(tc_name, result)
)
write_test_footer(tc_name)
@@ -1781,11 +1778,9 @@ def test_BGP_GR_TC_17_p1(request):
)
assert result is not True, (
"Testcase {} : Failed \n "
- "r1: routes are still present in BGP RIB\n Error: {}".format(
- tc_name, result
- )
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
# Verifying RIB routes
protocol = "bgp"
@@ -1794,9 +1789,9 @@ def test_BGP_GR_TC_17_p1(request):
)
assert result is not True, (
"Testcase {} : Failed \n "
- "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result)
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
logger.info("[Phase 5] : R2 is about to come up now ")
start_router_daemons(tgen, "r2", ["bgpd"])
@@ -1817,10 +1812,10 @@ def test_BGP_GR_TC_17_p1(request):
result = verify_r_bit(
tgen, topo, addr_type, input_dict, dut="r1", peer="r2", expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n " "r1: R-bit is set to True\n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: R-bit should not be set to True in r1\n"
+ "Found: {}".format(tc_name, result)
)
# Verifying BGP RIB routes
@@ -2026,10 +2021,10 @@ def test_BGP_GR_TC_43_p1(request):
result = verify_rib(
tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} :Failed \n Routes are still present \n Error {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
dut = "r2"
@@ -2043,18 +2038,18 @@ def test_BGP_GR_TC_43_p1(request):
)
assert result is not True, (
"Testcase {} : Failed \n "
- "r2: routes are still present in BGP RIB\n Error: {}".format(
- tc_name, result
- )
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
+
protocol = "bgp"
result = verify_rib(
tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} :Failed \n Routes are still present \n Error {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
step(
@@ -2353,17 +2348,17 @@ def test_BGP_GR_TC_44_p1(request):
)
assert result is not True, (
"Testcase {} : Failed \n "
- "r1: routes are still present in BGP RIB\n Error: {}".format(
- tc_name, result
- )
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
+
result = verify_rib(
tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} :Failed \n Routes are still present \n Error {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
step("Bring up BGPd on R2 and remove GR related config from R1 in global level")
diff --git a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-4.py b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-4.py
index 835ef41de..f408ff485 100644
--- a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-4.py
+++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-4.py
@@ -160,7 +160,7 @@ def setup_module(mod):
# Required linux kernel version for this suite to run.
result = required_linux_kernel_version("4.16")
if result is not True:
- pytest.skip("Kernel requirements are not met")
+ pytest.skip("Kernel requirements are not met, kernel version should be >=4.16")
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
@@ -1157,7 +1157,8 @@ def test_BGP_GR_TC_48_p1(request):
)
assert result is not True, (
"Testcase {} : Failed \n "
- "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result)
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
dut = "r2"
@@ -1171,16 +1172,17 @@ def test_BGP_GR_TC_48_p1(request):
)
assert result is not True, (
"Testcase {} : Failed \n "
- "r2: routes are still present in BGP RIB\n Error: {}".format(
- tc_name, result
- )
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
+
result = verify_rib(
tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False
)
assert result is not True, (
"Testcase {} : Failed \n "
- "r2: routes are still present in ZEBRA\n Error: {}".format(tc_name, result)
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
step("Bring up BGP on R1 and remove Peer-level GR config from R1")
@@ -1542,16 +1544,17 @@ def BGP_GR_TC_52_p1(request):
)
assert result is not True, (
"Testcase {} : Failed \n "
- "r1: routes are still present in BGP RIB\n Error: {}".format(
- tc_name, result
- )
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
+
result = verify_rib(
tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False
)
assert result is not True, (
"Testcase {} : Failed \n "
- "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result)
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
step("Bring up BGP on R2 and remove Peer-level GR config from R1")
diff --git a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-1.py b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-1.py
index 3afe38857..293f3042e 100644
--- a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-1.py
+++ b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-1.py
@@ -155,7 +155,7 @@ def setup_module(mod):
# Required linux kernel version for this suite to run.
result = required_linux_kernel_version("4.16")
if result is not True:
- pytest.skip("Kernel requirements are not met")
+ pytest.skip("Kernel requirements are not met, kernel version should be >=4.16")
global ADDR_TYPES
@@ -528,10 +528,10 @@ def test_BGP_GR_TC_3_p0(request):
result = verify_eor(
tgen, topo, addr_type, input_dict, dut="r2", peer="r1", expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n " "r2: EOR is set to True\n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: EOR should not be set to True in r2\n"
+ "Found: {}".format(tc_name, result)
)
logger.info(
@@ -675,10 +675,10 @@ def test_BGP_GR_TC_11_p0(request):
result = verify_eor(
tgen, topo, addr_type, input_dict, dut="r1", peer="r3", expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n " "r1: EOR is set to True\n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: EOR should not be set to True in r1\n"
+ "Found: {}".format(tc_name, result)
)
logger.info(
@@ -706,10 +706,10 @@ def test_BGP_GR_TC_11_p0(request):
result = verify_eor(
tgen, topo, addr_type, input_dict, dut="r3", peer="r1", expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n " "r3: EOR is set to True\n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: EOR should not be set to True in r3\n"
+ "Found: {}".format(tc_name, result)
)
write_test_footer(tc_name)
@@ -1474,38 +1474,33 @@ def test_BGP_GR_18_p1(request):
result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
- "r6: routes are still present in BGP RIB\n Error: {}".format(
- tc_name, result
- )
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, 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 "
- "r6: routes are still present in ZEBRA\n Error: {}".format(tc_name, result)
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, 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 "
- "r2: routes are still present in BGP RIB\n Error: {}".format(
- tc_name, result
- )
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, 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 "
- "r6: routes are still present in ZEBRA\n Error: {}".format(tc_name, result)
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
write_test_footer(tc_name)
diff --git a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-2.py b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-2.py
index 535f272ef..fe885372d 100644
--- a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-2.py
+++ b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-2.py
@@ -155,7 +155,7 @@ def setup_module(mod):
# Required linux kernel version for this suite to run.
result = required_linux_kernel_version("4.16")
if result is not True:
- pytest.skip("Kernel requirements are not met")
+ pytest.skip("Kernel requirements are not met, kernel version should be >=4.16")
global ADDR_TYPES
@@ -726,19 +726,17 @@ def test_BGP_GR_chaos_29_p1(request):
result = verify_bgp_rib(tgen, addr_type, dut, input_dict, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
- "r3: routes are still present in BGP RIB\n Error: {}".format(
- tc_name, result
- )
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, 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 "
- "r3: routes are still present in ZEBRA\n Error: {}".format(tc_name, result)
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
logger.info("[Step 4] : Start BGPd daemon on R1..")
@@ -981,11 +979,9 @@ def test_BGP_GR_chaos_33_p1(request):
)
assert result is not True, (
"Testcase {} : Failed \n "
- "r3: routes are still present in BGP RIB\n Error: {}".format(
- tc_name, result
- )
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
if addr_type == "ipv6":
if "link_local" in PREFERRED_NEXT_HOP:
@@ -998,11 +994,9 @@ def test_BGP_GR_chaos_33_p1(request):
)
assert result is not True, (
"Testcase {} : Failed \n "
- "r3: routes are still present in ZEBRA\n Error: {}".format(
- tc_name, result
- )
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
logger.info("[Step 4] : Start BGPd daemon on R1 and R4..")
@@ -1182,31 +1176,28 @@ def test_BGP_GR_chaos_34_2_p1(request):
result = verify_f_bit(
tgen, topo, addr_type, input_dict, "r3", "r1", expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n " "r3: F-bit is set to True\n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: F-bit should not be set to True in r3\n"
+ "Found: {}".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 "
- "r3: routes are still present in BGP RIB\n Error: {}".format(
- tc_name, result
- )
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, 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 "
- "r3: routes are still present in ZEBRA\n Error: {}".format(tc_name, result)
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
write_test_footer(tc_name)
diff --git a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-3.py b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-3.py
index e60552ed1..4ff62a978 100644
--- a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-3.py
+++ b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-3.py
@@ -155,7 +155,7 @@ def setup_module(mod):
# Required linux kernel version for this suite to run.
result = required_linux_kernel_version("4.16")
if result is not True:
- pytest.skip("Kernel requirements are not met")
+ pytest.skip("Kernel requirements are not met, kernel version should be >=4.16")
global ADDR_TYPES
@@ -380,12 +380,11 @@ def test_BGP_GR_chaos_34_1_p1(request):
result = verify_f_bit(
tgen, topo, addr_type, input_dict_2, "r3", "r1", expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n " "r3: F-bit is set to True\n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: F-bit should not be set to True in r3\n"
+ "Found: {}".format(tc_name, result)
)
- logger.info(" Expected behavior: {}".format(result))
logger.info("[Step 3] : Kill BGPd daemon on R1..")
@@ -402,19 +401,17 @@ def test_BGP_GR_chaos_34_1_p1(request):
result = verify_bgp_rib(tgen, addr_type, dut, input_dict, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
- "r3: routes are still present in BGP RIB\n Error: {}".format(
- tc_name, result
- )
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, 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 "
- "r3: routes are still present in ZEBRA\n Error: {}".format(tc_name, result)
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
# Start BGPd daemon on R1
start_router_daemons(tgen, "r1", ["bgpd"])
@@ -587,31 +584,28 @@ def test_BGP_GR_chaos_32_p1(request):
result = verify_eor(
tgen, topo, addr_type, input_dict_3, dut="r5", peer="r1", expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n " "r5: EOR is set to TRUE\n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: EOR should not be set to True in r5\n"
+ "Found: {}".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 "
- "r3: routes are still present in BGP RIB\n Error: {}".format(
- tc_name, result
- )
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, 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 "
- "r3: routes are still present in ZEBRA\n Error: {}".format(tc_name, result)
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
write_test_footer(tc_name)
@@ -716,12 +710,11 @@ def test_BGP_GR_chaos_37_p1(request):
result = verify_eor(
tgen, topo, addr_type, input_dict, dut="r3", peer="r1", expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n " "r3: EOR is set to True\n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: EOR should not be set to True in r3\n"
+ "Found: {}".format(tc_name, result)
)
- logger.info(" Expected behavior: {}".format(result))
# Verifying BGP RIB routes after starting BGPd daemon
dut = "r1"
@@ -783,10 +776,10 @@ def test_BGP_GR_chaos_37_p1(request):
result = verify_eor(
tgen, topo, addr_type, input_dict_3, dut="r1", peer="r3", expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n " "r1: EOR is set to True\n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: EOR should not be set to True in r1\n"
+ "Found: {}".format(tc_name, result)
)
write_test_footer(tc_name)
@@ -941,19 +934,17 @@ def test_BGP_GR_chaos_30_p1(request):
result = verify_bgp_rib(tgen, addr_type, dut, input_dict, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
- "r1: routes are still present in BGP RIB\n Error: {}".format(
- tc_name, result
- )
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, 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 "
- "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result)
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
write_test_footer(tc_name)
@@ -1356,7 +1347,8 @@ def BGP_GR_TC_7_p1(request):
result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
- "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result)
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
write_test_footer(tc_name)
diff --git a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-4.py b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-4.py
index 1df77ebeb..fd1ef097c 100644
--- a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-4.py
+++ b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-4.py
@@ -157,7 +157,7 @@ def setup_module(mod):
# Required linux kernel version for this suite to run.
result = required_linux_kernel_version("4.16")
if result is not True:
- pytest.skip("Kernel requirements are not met")
+ pytest.skip("Kernel requirements are not met, kernel version should be >=4.16")
global ADDR_TYPES
@@ -420,10 +420,10 @@ def test_BGP_GR_TC_23_p1(request):
result = verify_eor(
tgen, topo, addr_type, input_dict, dut="r1", peer="r2", expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n " "r1: EOR is set to True\n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: EOR should not be set to True in r2\n"
+ "Found: {}".format(tc_name, result)
)
# Verifying BGP RIB routes received from router R1
@@ -547,19 +547,17 @@ def test_BGP_GR_20_p1(request):
result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False)
assert result is not True, (
"Testcase {} : Failed \n "
- "r3: routes are still present in BGP RIB\n Error: {}".format(
- tc_name, result
- )
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, 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 "
- "r3: routes are still present in ZEBRA\n Error: {}".format(tc_name, result)
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info(" Expected behavior: {}".format(result))
# Start BGPd daemon on R1
start_router_daemons(tgen, "r1", ["bgpd"])
diff --git a/tests/topotests/bgp_gr_functionality_topo3/bgp_gr_functionality_topo3.py b/tests/topotests/bgp_gr_functionality_topo3/bgp_gr_functionality_topo3.py
index 6bf8b9630..76522206a 100644
--- a/tests/topotests/bgp_gr_functionality_topo3/bgp_gr_functionality_topo3.py
+++ b/tests/topotests/bgp_gr_functionality_topo3/bgp_gr_functionality_topo3.py
@@ -56,15 +56,20 @@ from lib.bgp import (
verify_graceful_restart_timers,
verify_bgp_convergence_from_running_config,
)
+
# Import common_config to use commomnly used APIs
-from lib.common_config import (create_common_configuration,
- InvalidCLIError, retry,
- generate_ips, FRRCFG_FILE,
- find_interface_with_greater_ip,
- check_address_types,
- validate_ip_address,
- run_frr_cmd,
- get_frr_ipv6_linklocal)
+from lib.common_config import (
+ create_common_configuration,
+ InvalidCLIError,
+ retry,
+ generate_ips,
+ FRRCFG_FILE,
+ find_interface_with_greater_ip,
+ check_address_types,
+ validate_ip_address,
+ run_frr_cmd,
+ get_frr_ipv6_linklocal,
+)
from lib.common_config import (
write_test_header,
@@ -108,8 +113,7 @@ NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"}
PREFERRED_NEXT_HOP = "link_local"
-def configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name,
- dut, peer):
+def configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut, peer):
"""
result = configure_gr_followed_by_clear(tgen, topo, dut)
assert result is True, \
@@ -118,8 +122,7 @@ def configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name,
"""
result = create_router_bgp(tgen, topo, input_dict)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, result)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
for addr_type in ADDR_TYPES:
clear_bgp(tgen, addr_type, dut)
@@ -131,6 +134,7 @@ def configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name,
return True
+
def verify_stale_routes_list(tgen, addr_type, dut, input_dict):
"""
This API is use verify Stale routes on refering the network with next hop value
@@ -175,8 +179,8 @@ def verify_stale_routes_list(tgen, addr_type, dut, input_dict):
command = "show bgp"
# Static routes
sleep(2)
- logger.info('Checking router {} BGP RIB:'.format(dut))
- if 'static_routes' in input_dict[routerInput]:
+ logger.info("Checking router {} BGP RIB:".format(dut))
+ if "static_routes" in input_dict[routerInput]:
static_routes = input_dict[routerInput]["static_routes"]
for static_route in static_routes:
found_routes = []
@@ -185,30 +189,27 @@ def verify_stale_routes_list(tgen, addr_type, dut, input_dict):
nh_found = False
vrf = static_route.setdefault("vrf", None)
community = static_route.setdefault("community", None)
- largeCommunity = \
- static_route.setdefault("largeCommunity", None)
+ largeCommunity = static_route.setdefault("largeCommunity", None)
if vrf:
- cmd = "{} vrf {} {}".\
- format(command, vrf, addr_type)
+ cmd = "{} vrf {} {}".format(command, vrf, addr_type)
if community:
- cmd = "{} community {}".\
- format(cmd, community)
+ cmd = "{} community {}".format(cmd, community)
if largeCommunity:
- cmd = "{} large-community {}".\
- format(cmd, largeCommunity)
+ cmd = "{} large-community {}".format(cmd, largeCommunity)
else:
- cmd = "{} {}".\
- format(command, addr_type)
+ cmd = "{} {}".format(command, addr_type)
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) == False:
- errormsg = "[DUT: {}]: No route found in rib of router". \
- format(router)
+ errormsg = "[DUT: {}]: No route found in rib of router".format(
+ router
+ )
return errormsg
elif "warning" in rib_routes_json:
- errormsg = "[DUT: {}]: {}". \
- format(router, rib_routes_json["warning"])
+ errormsg = "[DUT: {}]: {}".format(
+ router, rib_routes_json["warning"]
+ )
return errormsg
network = static_route["network"]
if "no_of_ip" in static_route:
@@ -227,15 +228,18 @@ def verify_stale_routes_list(tgen, addr_type, dut, input_dict):
st_found = True
found_routes.append(st_rt)
- for mnh in range(0, len(rib_routes_json[
- 'routes'][st_rt])):
- found_hops.append([rib_r[
- "ip"] for rib_r in rib_routes_json[
- 'routes'][st_rt][
- mnh]["nexthops"]])
+ for mnh in range(0, len(rib_routes_json["routes"][st_rt])):
+ found_hops.append(
+ [
+ rib_r["ip"]
+ for rib_r in rib_routes_json["routes"][st_rt][
+ mnh
+ ]["nexthops"]
+ ]
+ )
return found_hops
else:
- return 'error msg - no hops found'
+ return "error msg - no hops found"
def setup_module(mod):
@@ -248,7 +252,7 @@ def setup_module(mod):
# Required linux kernel version for this suite to run.
result = required_linux_kernel_version("4.16")
if result is not True:
- pytest.skip("Kernel requirements are not met")
+ pytest.skip("Kernel requirements are not met, kernel version should be >=4.16")
global ADDR_TYPES
@@ -302,6 +306,8 @@ def teardown_module(mod):
"Testsuite end time: {}".format(time.asctime(time.localtime(time.time())))
)
logger.info("=" * 40)
+
+
################################################################################
#
# TEST CASES
@@ -318,175 +324,160 @@ def test_bgp_gr_stale_routes(request):
step("Creating 5 static Routes in Router R3 with NULL0 as Next hop")
for addr_type in ADDR_TYPES:
- input_dict_1 = {
- "r3": {
- "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]
- },
- {
- "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]],
- "next_hop": NEXT_HOP_IP[addr_type]
- },
- {
- "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]],
- "next_hop": NEXT_HOP_IP[addr_type]
- },
- {
- "network": [NETWORK5_1[addr_type]] + [NETWORK5_2[addr_type]],
- "next_hop": NEXT_HOP_IP[addr_type]
- }]
- }
+ input_dict_1 = {
+ "r3": {
+ "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],
+ },
+ {
+ "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ {
+ "network": [NETWORK5_1[addr_type]] + [NETWORK5_2[addr_type]],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ },
+ ]
}
- result = create_static_routes(tgen, input_dict_1)
- assert result is True, 'Testcase {} : Failed \n Error: {}'.format(
- tc_name, result)
+ }
+ result = create_static_routes(tgen, input_dict_1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
step("verifying Created Route at R3 in VRF default")
for addr_type in ADDR_TYPES:
- dut = 'r3'
- input_dict_1= {'r3': topo['routers']['r3']}
+ dut = "r3"
+ input_dict_1 = {"r3": topo["routers"]["r3"]}
result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1)
- assert result is True, \
- "Testcase {} :Failed \n Error {}". \
- format(tc_name, result)
- #done
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+ # done
step("verifying Created Route at R2 in VRF default")
for addr_type in ADDR_TYPES:
- dut = 'r2'
- input_dict_1= {'r2': topo['routers']['r2']}
+ dut = "r2"
+ input_dict_1 = {"r2": topo["routers"]["r2"]}
result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1)
- assert result is True, \
- "Testcase {} :Failed \n Error {}". \
- format(tc_name, result)
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
step("importing vrf RED on R2 under Address Family")
for addr_type in ADDR_TYPES:
- input_import_vrf={
+ input_import_vrf = {
"r2": {
"bgp": [
{
"local_as": 200,
"vrf": "RED",
- "address_family": {addr_type: {"unicast": {"import": {"vrf": "default"}}}},
+ "address_family": {
+ addr_type: {"unicast": {"import": {"vrf": "default"}}}
+ },
}
]
}
}
- result = create_router_bgp(tgen, topo,input_import_vrf)
- assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
- #done
+ result = create_router_bgp(tgen, topo, input_import_vrf)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ # done
step("verifying static Routes at R2 in VRF RED")
for addr_type in ADDR_TYPES:
- dut = 'r2'
- input_dict_1= {'r2': topo['routers']['r2']}
+ dut = "r2"
+ input_dict_1 = {"r2": topo["routers"]["r2"]}
result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1)
- assert result is True, \
- "Testcase {} :Failed \n Error {}". \
- format(tc_name, result)
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
step("verifying static Routes at R1 in VRF RED")
for addr_type in ADDR_TYPES:
- dut = 'r1'
- input_dict_1= {'r1': topo['routers']['r1']}
+ dut = "r1"
+ input_dict_1 = {"r1": topo["routers"]["r1"]}
result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1)
- assert result is True, \
- "Testcase {} :Failed \n Error {}". \
- format(tc_name, result)
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
step("Configuring Graceful restart at R2 and R3 ")
input_dict = {
"r2": {
-
"bgp": {
"local_as": "200",
"graceful-restart": {
"graceful-restart": True,
- }
+ },
}
},
"r3": {
- "bgp": {
- "local_as": "300",
- "graceful-restart": {
- "graceful-restart": True
- }
- }
- }
+ "bgp": {"local_as": "300", "graceful-restart": {"graceful-restart": True}}
+ },
}
- configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name,dut='r2', peer='r3')
-
-
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r2", peer="r3")
step("verify Graceful restart at R2")
for addr_type in ADDR_TYPES:
- result = verify_graceful_restart(tgen, topo, addr_type, input_dict,
- dut='r2', peer='r3')
- assert result is True, \
- "Testcase {} :Failed \n Error {}". \
- format(tc_name, result)
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r2", peer="r3"
+ )
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
step("verify Graceful restart at R3")
for addr_type in ADDR_TYPES:
- result = verify_graceful_restart(tgen, topo, addr_type, input_dict,
- dut='r3', peer='r2')
- assert result is True, \
- "Testcase {} :Failed \n Error {}". \
- format(tc_name, result)
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r3", peer="r2"
+ )
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
step("Configuring Graceful-restart-disable at R3")
input_dict = {
"r2": {
-
"bgp": {
"local_as": "200",
"graceful-restart": {
"graceful-restart": False,
- }
+ },
}
},
"r3": {
- "bgp": {
- "local_as": "300",
- "graceful-restart": {
- "graceful-restart": False
- }
- }
- }
+ "bgp": {"local_as": "300", "graceful-restart": {"graceful-restart": False}}
+ },
}
- configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name,dut='r3', peer='r2')
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r3", peer="r2")
step("Verify Graceful-restart-disable at R3")
for addr_type in ADDR_TYPES:
- result = verify_graceful_restart(tgen, topo, addr_type, input_dict,
- dut='r3', peer='r2')
- assert result is True, \
- "Testcase {} :Failed \n Error {}". \
- format(tc_name, result)
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r3", peer="r2"
+ )
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
for iteration in range(5):
step("graceful-restart-disable:True at R3")
input_dict = {
- "r3": {
- "bgp": {
- "graceful-restart": {
- "graceful-restart-disable": True,
+ "r3": {
+ "bgp": {
+ "graceful-restart": {
+ "graceful-restart-disable": True,
+ }
}
}
- }
}
- configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name,
- dut='r3', peer='r2')
+ configure_gr_followed_by_clear(
+ tgen, topo, input_dict, tc_name, dut="r3", peer="r2"
+ )
step("Verifying Routes at R2 on enabling GRD")
- dut = 'r2'
+ dut = "r2"
for addr_type in ADDR_TYPES:
- input_dict_1= {'r2': topo['routers']['r2']}
+ input_dict_1 = {"r2": topo["routers"]["r2"]}
result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1)
- assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+ assert result is True, "Testcase {} :Failed \n Error {}".format(
+ tc_name, result
+ )
step("Verify stale Routes in Router R2 enabling GRD")
for addr_type in ADDR_TYPES:
@@ -495,39 +486,45 @@ def test_bgp_gr_stale_routes(request):
verify_nh_for_static_rtes = {
"r3": {
"static_routes": [
-
{
"network": [NETWORK1_1[addr_type]],
"no_of_ip": 2,
- "vrf": "RED"
+ "vrf": "RED",
}
]
}
}
bgp_rib_next_hops = verify_stale_routes_list(
- tgen, addr_type, dut, verify_nh_for_static_rtes)
- assert (len(bgp_rib_next_hops)== 1) is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, bgp_rib_next_hops,expected=True)
+ tgen, addr_type, dut, verify_nh_for_static_rtes
+ )
+ assert (
+ len(bgp_rib_next_hops) == 1
+ ) is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, bgp_rib_next_hops, expected=True
+ )
step("graceful-restart-disable:False at R3")
input_dict = {
- "r3": {
- "bgp": {
- "graceful-restart": {
- "graceful-restart-disable": False,
+ "r3": {
+ "bgp": {
+ "graceful-restart": {
+ "graceful-restart-disable": False,
+ }
}
}
- }
}
- configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name,
- dut='r3', peer='r2')
+ configure_gr_followed_by_clear(
+ tgen, topo, input_dict, tc_name, dut="r3", peer="r2"
+ )
step("Verifying Routes at R2 on disabling GRD")
- dut = 'r2'
+ dut = "r2"
for addr_type in ADDR_TYPES:
- input_dict_1= {'r2': topo['routers']['r2']}
+ input_dict_1 = {"r2": topo["routers"]["r2"]}
result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1)
- assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+ assert result is True, "Testcase {} :Failed \n Error {}".format(
+ tc_name, result
+ )
step("Verify stale Routes in Router R2 on disabling GRD")
for addr_type in ADDR_TYPES:
@@ -536,19 +533,22 @@ def test_bgp_gr_stale_routes(request):
verify_nh_for_static_rtes = {
"r3": {
"static_routes": [
-
{
"network": [NETWORK1_1[addr_type]],
"no_of_ip": 2,
- "vrf": "RED"
+ "vrf": "RED",
}
]
}
}
- bgp_rib_next_hops = verify_stale_routes_list(tgen, addr_type, dut, verify_nh_for_static_rtes)
-
- stale_route_status=len(bgp_rib_next_hops)== 1
- assert stale_route_status is True, "Testcase {} : Failed \n Error: {}".format(
- tc_name, stale_route_status,expected=True)
+ bgp_rib_next_hops = verify_stale_routes_list(
+ tgen, addr_type, dut, verify_nh_for_static_rtes
+ )
+
+ stale_route_status = len(bgp_rib_next_hops) == 1
+ assert (
+ stale_route_status is True
+ ), "Testcase {} : Failed \n Error: {}".format(
+ tc_name, stale_route_status, expected=True
+ )
write_test_footer(tc_name)
-
diff --git a/tests/topotests/bgp_gr_restart_retain_routes/r2/zebra.conf b/tests/topotests/bgp_gr_restart_retain_routes/r2/zebra.conf
index c03dd7e19..758d797ad 100644
--- a/tests/topotests/bgp_gr_restart_retain_routes/r2/zebra.conf
+++ b/tests/topotests/bgp_gr_restart_retain_routes/r2/zebra.conf
@@ -1,3 +1,4 @@
+no zebra nexthop kernel enable
!
interface r2-eth0
ip address 192.168.255.2/24
diff --git a/tests/topotests/bgp_gshut_topo1/test_ebgp_gshut_topo1.py b/tests/topotests/bgp_gshut_topo1/test_ebgp_gshut_topo1.py
index 58133c44a..684d2fcb5 100644
--- a/tests/topotests/bgp_gshut_topo1/test_ebgp_gshut_topo1.py
+++ b/tests/topotests/bgp_gshut_topo1/test_ebgp_gshut_topo1.py
@@ -92,7 +92,7 @@ def setup_module(mod):
# Required linux kernel version for this suite to run.
result = required_linux_kernel_version("4.16")
if result is not True:
- pytest.skip("Kernel requirements are not met")
+ pytest.skip("Kernel requirements are not met, kernel version should be >=4.16")
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
diff --git a/tests/topotests/bgp_gshut_topo1/test_ibgp_gshut_topo1.py b/tests/topotests/bgp_gshut_topo1/test_ibgp_gshut_topo1.py
index a79ce0e3a..16572a796 100644
--- a/tests/topotests/bgp_gshut_topo1/test_ibgp_gshut_topo1.py
+++ b/tests/topotests/bgp_gshut_topo1/test_ibgp_gshut_topo1.py
@@ -87,7 +87,7 @@ def setup_module(mod):
# Required linux kernel version for this suite to run.
result = required_linux_kernel_version("4.16")
if result is not True:
- pytest.skip("Kernel requirements are not met")
+ pytest.skip("Kernel requirements are not met, kernel version should be >=4.16")
testsuite_run_time = time.asctime(time.localtime(time.time()))
logger.info("Testsuite start time: {}".format(testsuite_run_time))
diff --git a/tests/topotests/bgp_local_asn/bgp_local_asn_agg.json b/tests/topotests/bgp_local_asn/bgp_local_asn_agg.json
new file mode 100644
index 000000000..a842c9eb2
--- /dev/null
+++ b/tests/topotests/bgp_local_asn/bgp_local_asn_agg.json
@@ -0,0 +1,147 @@
+{
+ "address_types": ["ipv4", "ipv6"],
+ "ipv4base": "10.0.0.0",
+ "ipv4mask": 30,
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {"ipv4": "10.0.0.0", "v4mask": 30, "ipv6": "fd00::", "v6mask": 64},
+ "lo_prefix": {"ipv4": "1.0.", "v4mask": 32, "ipv6": "2001:db8:f::", "v6mask": 128},
+ "routers": {
+ "r1": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r3": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp": {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"}
+ ],
+ "neighbor": {
+ "r3": {"dest_link": {"r1": {}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"}
+ ],
+ "neighbor": {
+ "r3": {"dest_link": {"r1": {}}}
+ }
+ }
+ }
+ }
+ },
+ "static_routes":[
+ {
+ "network":"10.1.1.0/32",
+ "next_hop":"Null0"
+ },
+ {
+ "network":"10:1::1:0/128",
+ "next_hop":"Null0"
+ }]
+ },
+ "r2": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r3": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp": {
+ "local_as": "200",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"}
+ ],
+ "neighbor": {
+ "r3": {"dest_link": {"r2": {}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"}
+ ],
+ "neighbor": {
+ "r3": {"dest_link": {"r2": {}}}
+ }
+ }
+ }
+ }
+ },
+ "static_routes":[
+ {
+ "network":"10.1.2.0/32",
+ "next_hop":"Null0"
+ },
+ {
+ "network":"10:1::2:0/128",
+ "next_hop":"Null0"
+ }]
+ },
+ "r3": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r1": {"ipv4": "auto", "ipv6": "auto"},
+ "r2": {"ipv4": "auto", "ipv6": "auto"},
+ "r4": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp": {
+ "local_as": "300",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {"dest_link": {"r3": {}}},
+ "r2": {"dest_link": {"r3": {}}},
+ "r4": {"dest_link": {"r3": {}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {"dest_link": {"r3": {}}},
+ "r2": {"dest_link": {"r3": {}}},
+ "r4": {"dest_link": {"r3": {}}}
+ }
+ }
+ }
+ }
+ }
+ },
+ "r4": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r3": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp": {
+ "local_as": "400",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {"dest_link": {"r4": {}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {"dest_link": {"r4": {}}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_local_asn/bgp_local_asn_ecmp.json b/tests/topotests/bgp_local_asn/bgp_local_asn_ecmp.json
new file mode 100644
index 000000000..7184679e9
--- /dev/null
+++ b/tests/topotests/bgp_local_asn/bgp_local_asn_ecmp.json
@@ -0,0 +1,317 @@
+{
+ "address_types": [
+ "ipv4",
+ "ipv6"
+ ],
+ "ipv4base": "10.0.0.0",
+ "ipv4mask": 24,
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {
+ "ipv4": "10.0.0.0",
+ "v4mask": 24,
+ "ipv6": "fd00::",
+ "v6mask": 64
+ },
+ "lo_prefix": {
+ "ipv4": "1.0.",
+ "v4mask": 32,
+ "ipv6": "2001:DB8:F::",
+ "v6mask": 128
+ },
+ "routers": {
+ "r1": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r2-link1": {
+ "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":"10.0.0.1/32",
+ "next_hop":"Null0"
+ },
+ {
+ "network":"10::1/128",
+ "next_hop":"Null0"
+ }
+ ]
+ },
+ "r2": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r1-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": [{
+ "local_as": "200",
+ "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": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "r3": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r2-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r4-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r4-link2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r4-link3": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r4-link4": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r4-link5": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r4-link6": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r4-link7": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r4-link8": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": [{
+ "local_as": "300",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {}
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3-link1": {},
+ "r3-link2": {},
+ "r3-link3": {},
+ "r3-link4": {},
+ "r3-link5": {},
+ "r3-link6": {},
+ "r3-link7": {},
+ "r3-link8": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {}
+ }
+ },
+ "r4": {
+ "dest_link": {
+ "r3-link1": {},
+ "r3-link2": {},
+ "r3-link3": {},
+ "r3-link4": {},
+ "r3-link5": {},
+ "r3-link6": {},
+ "r3-link7": {},
+ "r3-link8": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "r4": {
+ "links": {
+ "lo": {
+ "ipv4": "auto",
+ "ipv6": "auto",
+ "type": "loopback"
+ },
+ "r3-link1": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link2": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link3": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link4": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link5": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link6": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link7": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ },
+ "r3-link8": {
+ "ipv4": "auto",
+ "ipv6": "auto"
+ }
+ },
+ "bgp": [{
+ "local_as": "400",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r4-link1": {},
+ "r4-link2": {},
+ "r4-link3": {},
+ "r4-link4": {},
+ "r4-link5": {},
+ "r4-link6": {},
+ "r4-link7": {},
+ "r4-link8": {}
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r4-link1": {},
+ "r4-link2": {},
+ "r4-link3": {},
+ "r4-link4": {},
+ "r4-link5": {},
+ "r4-link6": {},
+ "r4-link7": {},
+ "r4-link8": {}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/topotests/bgp_local_asn/bgp_local_asn_topo1.json b/tests/topotests/bgp_local_asn/bgp_local_asn_topo1.json
new file mode 100644
index 000000000..da665bed0
--- /dev/null
+++ b/tests/topotests/bgp_local_asn/bgp_local_asn_topo1.json
@@ -0,0 +1,132 @@
+{
+ "address_types": ["ipv4", "ipv6"],
+ "ipv4base": "10.0.0.0",
+ "ipv4mask": 30,
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {"ipv4": "10.0.0.0", "v4mask": 30, "ipv6": "fd00::", "v6mask": 64},
+ "lo_prefix": {"ipv4": "1.0.", "v4mask": 32, "ipv6": "2001:db8:f::", "v6mask": 128},
+ "routers": {
+ "r1": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r2": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp": {
+ "local_as": "100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"}
+ ],
+ "neighbor": {
+ "r2": {"dest_link": {"r1": {}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"}
+ ],
+ "neighbor": {
+ "r2": {"dest_link": {"r1": {}}}
+ }
+ }
+ }
+ }
+ },
+ "static_routes":[
+ {
+ "network":"10.1.1.0/32",
+ "next_hop":"Null0"
+ },
+ {
+ "network":"10:1::1:0/128",
+ "next_hop":"Null0"
+ }]
+ },
+ "r2": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r1": {"ipv4": "auto", "ipv6": "auto"},
+ "r3": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp": {
+ "local_as": "200",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {"dest_link": {"r2": {}}},
+ "r3": {"dest_link": {"r2": {}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {"dest_link": {"r2": {}}},
+ "r3": {"dest_link": {"r2": {}}}
+ }
+ }
+ }
+ }
+ }
+ },
+ "r3": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r2": {"ipv4": "auto", "ipv6": "auto"},
+ "r4": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp": {
+ "local_as": "300",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {"dest_link": {"r3": {}}},
+ "r4": {"dest_link": {"r3": {}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {"dest_link": {"r3": {}}},
+ "r4": {"dest_link": {"r3": {}}}
+ }
+ }
+ }
+ }
+ }
+ },
+ "r4": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r3": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp": {
+ "local_as": "400",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {"dest_link": {"r4": {}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {"dest_link": {"r4": {}}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_local_asn/bgp_local_asn_topo2.json b/tests/topotests/bgp_local_asn/bgp_local_asn_topo2.json
new file mode 100644
index 000000000..51f9bb243
--- /dev/null
+++ b/tests/topotests/bgp_local_asn/bgp_local_asn_topo2.json
@@ -0,0 +1,117 @@
+{
+ "address_types": ["ipv4", "ipv6"],
+ "ipv4base": "10.0.0.0",
+ "ipv4mask": 30,
+ "ipv6base": "fd00::",
+ "ipv6mask": 64,
+ "link_ip_start": {"ipv4": "10.0.0.0", "v4mask": 30, "ipv6": "fd00::", "v6mask": 64},
+ "lo_prefix": {"ipv4": "1.0.", "v4mask": 32, "ipv6": "2001:db8:f::", "v6mask": 128},
+ "routers": {
+ "r1": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r2": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp": {
+ "local_as": "12000100",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {"dest_link": {"r1": {}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {"dest_link": {"r1": {}}}
+ }
+ }
+ }
+ }
+ }
+ },
+ "r2": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r1": {"ipv4": "auto", "ipv6": "auto"},
+ "r3": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp": {
+ "local_as": "12000200",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r1": {"dest_link": {"r2": {}}},
+ "r3": {"dest_link": {"r2": {}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r1": {"dest_link": {"r2": {}}},
+ "r3": {"dest_link": {"r2": {}}}
+ }
+ }
+ }
+ }
+ }
+ },
+ "r3": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r2": {"ipv4": "auto", "ipv6": "auto"},
+ "r4": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp": {
+ "local_as": "12000300",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {"dest_link": {"r3": {}}},
+ "r4": {"dest_link": {"r3": {}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {"dest_link": {"r3": {}}},
+ "r4": {"dest_link": {"r3": {}}}
+ }
+ }
+ }
+ }
+ }
+ },
+ "r4": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r3": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp": {
+ "local_as": "12000400",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {"dest_link": {"r4": {}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {"dest_link": {"r4": {}}}
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_local_asn/bgp_local_asn_vrf_topo1.json b/tests/topotests/bgp_local_asn/bgp_local_asn_vrf_topo1.json
new file mode 100644
index 000000000..d415b63ce
--- /dev/null
+++ b/tests/topotests/bgp_local_asn/bgp_local_asn_vrf_topo1.json
@@ -0,0 +1,152 @@
+{
+ "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": {
+ "r2": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+
+ "r3": {"ipv4": "auto", "ipv6": "auto"}
+ },
+ "bgp":[
+ {
+ "local_as": "200",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"}
+ ],
+ "neighbor": {
+
+ "r3": {"dest_link": {"r2": {}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"}
+ ],
+ "neighbor": {
+
+ "r3": {"dest_link": {"r2": {}}}
+ }
+ }
+ }
+ }
+ }
+ ],
+ "static_routes":[
+ {
+ "network":"10.0.0.1/32",
+ "next_hop":"Null0"
+ },
+ {
+ "network":"10::1/128",
+ "next_hop":"Null0"
+ }]
+ },
+ "r3": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r2": {"ipv4": "auto", "ipv6": "auto"},
+ "r4": {"ipv4": "auto", "ipv6": "auto","vrf": "BLUE"}
+ },
+ "vrfs":[
+ {
+ "name": "BLUE",
+ "id": "1"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "300",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {"r3": {}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {"r3": {}}}
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "300",
+ "vrf": "BLUE",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {"r3": {}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {"r3": {}}}
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "r4": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r3": {"ipv4": "auto", "ipv6": "auto","vrf": "BLUE"}
+ },
+ "vrfs":[
+ {
+ "name": "BLUE",
+ "id": "1"
+ }
+ ],
+ "bgp":
+ [
+ {
+ "local_as": "400",
+ "vrf": "BLUE",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {"r4": {}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {"r4": {}}}
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/topotests/bgp_local_asn/bgp_local_asn_vrf_topo2.json b/tests/topotests/bgp_local_asn/bgp_local_asn_vrf_topo2.json
new file mode 100644
index 000000000..311ccce69
--- /dev/null
+++ b/tests/topotests/bgp_local_asn/bgp_local_asn_vrf_topo2.json
@@ -0,0 +1,128 @@
+{
+ "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": {
+ "r2": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r3": {"ipv4": "auto", "ipv6": "auto","vrf": "RED"}
+ },
+ "vrfs":[{"name": "RED","id": "1"}],
+ "bgp":[
+ {
+ "local_as": "200",
+ "vrf": "RED",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {"dest_link": {"r2": {}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {"dest_link": {"r2": {}}}
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "r3": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r2": {"ipv4": "auto", "ipv6": "auto","vrf": "RED"},
+ "r4": {"ipv4": "auto", "ipv6": "auto","vrf": "BLUE"}
+ },
+ "vrfs":[{"name": "RED","id": "1"},
+ {"name": "BLUE","id": "2"}],
+ "bgp":
+ [
+ {
+ "local_as": "300",
+ "vrf": "RED",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {"r3": {}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {"r3": {}}}
+ }
+ }
+ }
+ }
+ },
+ {
+ "local_as": "300",
+ "vrf": "BLUE",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {"r3": {}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {"r3": {}}}
+ }
+ }
+ }
+ }
+ }
+ ]
+ },
+ "r4": {
+ "links": {
+ "lo": {"ipv4": "auto", "ipv6": "auto", "type": "loopback"},
+ "r3": {"ipv4": "auto", "ipv6": "auto","vrf": "BLUE"}
+ },
+ "vrfs":[{"name": "BLUE","id": "1"}],
+ "bgp":
+ [
+ {
+ "local_as": "400",
+ "vrf": "BLUE",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {"r4": {}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {"r4": {}}}
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+ }
+} \ No newline at end of file
diff --git a/tests/topotests/bgp_local_asn/test_bgp_local_asn_agg.py b/tests/topotests/bgp_local_asn/test_bgp_local_asn_agg.py
new file mode 100644
index 000000000..8f7e1285e
--- /dev/null
+++ b/tests/topotests/bgp_local_asn/test_bgp_local_asn_agg.py
@@ -0,0 +1,420 @@
+#!/usr/bin/env python3
+#
+# Copyright (c) 2022 by VMware, Inc. ("VMware")
+# Used Copyright (c) 2018 by Network Device Education Foundation,
+# Inc. ("NetDEF") in this file.
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+
+"""
+Following tests are covered to test BGP Multi-VRF Dynamic Route Leaking:
+1. Verify the BGP Local AS functionality by aggregating routes in between eBGP Peers.
+"""
+
+import os
+import sys
+import time
+import pytest
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib.topogen import Topogen, get_topogen
+from lib.topotest import version_cmp
+
+from lib.common_config import (
+ start_topology,
+ write_test_header,
+ write_test_footer,
+ reset_config_on_routers,
+ verify_rib,
+ step,
+ check_address_types,
+ check_router_status
+)
+
+from lib.topolog import logger
+from lib.bgp import (
+ verify_bgp_convergence,
+ verify_bgp_rib,
+ create_router_bgp,
+)
+from lib.topojson import build_config_from_json
+
+pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
+
+# Global variables
+BGP_CONVERGENCE = False
+ADDR_TYPES = check_address_types()
+NETWORK_1_1 = {"ipv4": "10.1.1.0/32", "ipv6": "10:1::1:0/128"}
+NETWORK_1_2 = {"ipv4": "10.1.2.0/32", "ipv6": "10:1::2:0/128"}
+AGGREGATE_NW = {"ipv4": "10.1.0.0/16", "ipv6": "10:1::/96"}
+NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"}
+
+
+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...
+ json_file = "{}/bgp_local_asn_agg.json".format(CWD)
+ tgen = Topogen(json_file, mod.__name__)
+ global topo
+ topo = tgen.json_topo
+ # ... and here it calls Mininet initialization functions.
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start daemons 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_verify_bgp_local_as_agg_in_EBGP_p0(request):
+ """
+ Verify the BGP Local AS functionality by aggregating routes in between eBGP Peers.
+ """
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ step("Base config is done as part of JSON")
+ step("Configure local-as at R3 towards R4.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ for dut, asn, neighbor in zip(["r2", "r4"], ["200", "400"], ["r3", "r3"]):
+ input_dict_r2_r4 = {
+ dut: {
+ "bgp": {
+ "local_as": asn,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ dut: {"local_asn": {"remote_as": "110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r2_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step("Done in base config: Advertise prefix 10.1.1.0/24 from Router-1(AS-100).")
+ step(
+ "Done in base config: Advertise an ipv6 prefix 10:1::1:0/120 from Router-1(AS-100)."
+ )
+ step("Verify that Static routes are redistributed in BGP process")
+ for addr_type in ADDR_TYPES:
+ input_static_verify_r1 = {
+ "r1": {"static_routes": [{"network": NETWORK_1_1[addr_type]}]}
+ }
+
+ input_static_verify_r2 = {
+ "r2": {"static_routes": [{"network": NETWORK_1_2[addr_type]}]}
+ }
+ result = verify_rib(tgen, addr_type, "r1", input_static_verify_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_rib(tgen, addr_type, "r2", input_static_verify_r2)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure aggregate-address to summarise all the advertised routes.")
+ for addr_type in ADDR_TYPES:
+ route_aggregate = {
+ "r3": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "aggregate_address": [
+ {
+ "network": AGGREGATE_NW[addr_type],
+ "summary": True,
+ "as_set": True,
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, route_aggregate)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that we see a summarised route on advertising router R3 "
+ "and receiving router R4 for both AFIs"
+ )
+
+ for addr_type in ADDR_TYPES:
+ input_static_agg_r1 = {
+ "r1": {"static_routes": [{"network": AGGREGATE_NW[addr_type]}]}
+ }
+ input_static_r1 = {
+ "r1": {"static_routes": [{"network": [NETWORK_1_1[addr_type]]}]}
+ }
+
+ input_static_r2 = {
+ "r2": {"static_routes": [{"network": [NETWORK_1_2[addr_type]]}]}
+ }
+
+ for dut in ["r3", "r4"]:
+ result = verify_rib(tgen, addr_type, dut, input_static_agg_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut, input_routes in zip(["r1", "r2"], [input_static_r1, input_static_r2]):
+ result = verify_rib(tgen, addr_type, dut, input_routes)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that AS-110 is got added in the AS list 110 {100,110,200} by following "
+ "commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "{100,110,200}"
+ for addr_type in ADDR_TYPES:
+ input_static_agg_r1 = {
+ "r1": {"static_routes": [{"network": AGGREGATE_NW[addr_type]}]}
+ }
+ result = verify_bgp_rib(
+ tgen, addr_type, dut, input_static_agg_r1, aspath=aspath
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend at R3 towards R4 & R2.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "110",
+ "no_prepend": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ dut = "r3"
+ aspath = "{100,200}"
+ for addr_type in ADDR_TYPES:
+ input_static_agg_r1 = {
+ "r1": {"static_routes": [{"network": AGGREGATE_NW[addr_type]}]}
+ }
+ result = verify_bgp_rib(
+ tgen, addr_type, dut, input_static_agg_r1, aspath=aspath
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend and replace-as at R3 towards R4 & R2.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "110",
+ "no_prepend": True,
+ "replace_as": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ dut = "r4"
+ aspath = "110 {100,200}"
+ for addr_type in ADDR_TYPES:
+ input_static_agg_r1 = {
+ "r1": {"static_routes": [{"network": AGGREGATE_NW[addr_type]}]}
+ }
+ result = verify_bgp_rib(
+ tgen, addr_type, dut, input_static_agg_r1, aspath=aspath
+ )
+ 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_local_asn/test_bgp_local_asn_ecmp.py b/tests/topotests/bgp_local_asn/test_bgp_local_asn_ecmp.py
new file mode 100644
index 000000000..d7c480d0b
--- /dev/null
+++ b/tests/topotests/bgp_local_asn/test_bgp_local_asn_ecmp.py
@@ -0,0 +1,524 @@
+#!/usr/bin/env python3
+#
+# Copyright (c) 2022 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.
+#
+#
+##########################################################################################################################################
+#
+# Testcases
+#
+###########################################################################################################################################
+###########################################################################################################################################
+#
+# 1.10.1.7. Verify the BGP Local AS functionality with ECMP on 8 links by adding no-prepend and replace-as command in between eBGP Peers.
+#
+#################################################################################################################################################
+
+import os
+import sys
+import time
+import pytest
+import platform
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib.topogen import Topogen, get_topogen
+from lib.topotest import version_cmp
+
+from lib.common_config import (
+ start_topology,
+ write_test_header,
+ create_static_routes,
+ write_test_footer,
+ reset_config_on_routers,
+ verify_rib,
+ step,
+ check_address_types,
+ check_router_status,
+ create_static_routes,
+ verify_fib_routes,
+)
+
+from lib.topolog import logger
+from lib.bgp import (
+ verify_bgp_convergence,
+ verify_bgp_rib,
+ create_router_bgp,
+)
+from lib.topojson import build_config_from_json
+
+pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
+
+# Global variables
+BGP_CONVERGENCE = False
+NETWORK = {"ipv4": "10.1.1.0/32", "ipv6": "10:1::1:0/128"}
+NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"}
+
+
+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...
+ json_file = "{}/bgp_local_asn_ecmp.json".format(CWD)
+ tgen = Topogen(json_file, mod.__name__)
+ global topo
+ topo = tgen.json_topo
+ # ... and here it calls Mininet initialization functions.
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start daemons 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_verify_bgp_local_as_in_ecmp_EBGP_p0(request):
+ """
+ Verify the BGP Local AS functionality with ECMP on 8 links by
+ adding no-prepend and replace-as command in between eBGP Peers.
+ """
+
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ step("Base config is done as part of JSON")
+ dut = "r1"
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ input_dict_static_route = {
+ "r1": {
+ "static_routes": [
+ {"network": NETWORK[addr_type], "next_hop": NEXT_HOP_IP[addr_type]}
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_static_route)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("configure redistribute static in Router BGP in R1")
+ input_dict_static_route_redist = {
+ "r1": {
+ "bgp": [
+ {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_static_route_redist)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify IPv4 and IPv6 static routes received on R1")
+ result = verify_rib(tgen, addr_type, "r1", input_dict_static_route)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_dict_static_route)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ result = verify_fib_routes(tgen, addr_type, "r1", input_dict_static_route)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as at R3 towards R2.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r3_to_r2 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {
+ "local_asn": {"local_as": "110"}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3_to_r2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as at R3 towards R4.")
+ dest_link = {}
+ for link_no in range(1, 9):
+ link = "r3-link" + str(link_no)
+ dest_link[link] = {"local_asn": {"local_as": "110"}}
+ for addr_type in ADDR_TYPES:
+ input_dict_r3_to_r4 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {"r4": {"dest_link": dest_link}}
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3_to_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure remote-as at R2 towards R3.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r2_to_r3 = {
+ "r2": {
+ "bgp": [
+ {
+ "local_as": "200",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2-link1": {
+ "local_asn": {"remote_as": "110"}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r2_to_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure remote-as at R4 towards R3.")
+ dest_link = {}
+ for link_no in range(1, 9):
+ link = "r4-link" + str(link_no)
+ dest_link[link] = {"local_asn": {"remote_as": "110"}}
+ for addr_type in ADDR_TYPES:
+ input_dict_r4_to_r3 = {
+ "r4": {
+ "bgp": [
+ {
+ "local_as": "400",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {"r3": {"dest_link": dest_link}}
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r4_to_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step("Verify IPv4 and IPv6 static routes received on R3 & R4")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r1": {
+ "static_routes": [
+ {"network": NETWORK[addr_type], "next_hop": NEXT_HOP_IP[addr_type]}
+ ]
+ }
+ }
+ for dut in ["r3", "r4"]:
+ result = verify_fib_routes(tgen, addr_type, dut, static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(tgen, addr_type, dut, static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that AS-110 is got added in the AS list 110 200 100 by following "
+ " commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "110 200 100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend at R3 towards R2.")
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_r3_to_r2 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {
+ "local_asn": {
+ "local_as": "110",
+ "no_prepend": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_no_prep_r3_to_r2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend at R3 towards R4.")
+ dest_link = {}
+ for link_no in range(1, 9):
+ link = "r3-link" + str(link_no)
+ dest_link[link] = {"local_asn": {"local_as": "110"}}
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_r3_to_r4 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {"r4": {"dest_link": dest_link}}
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_no_prep_r3_to_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ dut = "r3"
+ aspath = "200 100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r2": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend and replace-as at R3 towards R2")
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_rep_as_r3_to_r2 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3-link1": {
+ "local_asn": {
+ "local_as": "110",
+ "no_prepend": True,
+ "replace_as": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_no_prep_rep_as_r3_to_r2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend and replace-as at R3 towards R4")
+ dest_link = {}
+ for link_no in range(1, 9):
+ link = "r3-link" + str(link_no)
+ dest_link[link] = {
+ "local_asn": {"local_as": "110", "no_prepend": True, "replace_as": True}
+ }
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_rep_as_r3_to_r4 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {"r4": {"dest_link": dest_link}}
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_no_prep_rep_as_r3_to_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ dut = "r4"
+ aspath = "110 200 100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ 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_local_asn/test_bgp_local_asn_topo1.py b/tests/topotests/bgp_local_asn/test_bgp_local_asn_topo1.py
new file mode 100644
index 000000000..925980a43
--- /dev/null
+++ b/tests/topotests/bgp_local_asn/test_bgp_local_asn_topo1.py
@@ -0,0 +1,3655 @@
+#!/usr/bin/env python3
+#
+# Copyright (c) 2022 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.
+#
+
+##########################################################################################################
+#
+# Functionality Testcases
+#
+##########################################################################################################
+"""
+1. Verify the BGP Local AS functionality by adding no-prepend and replace-as command in between eBGP Peers.
+2. Verify the BGP Local AS functionality by configuring 4 Byte AS at R3 and 2 Byte AS at R2 & R4 in between eBGP Peers.
+3. Verify that BGP Local AS functionality by performing graceful restart in between eBGP Peers.
+4. Verify the BGP Local AS functionality by adding another AS & by same AS with AS-Prepend command in between eBGP Peers.
+4. Verify the BGP Local AS functionality by adding no-prepend and replace-as command in between iBGP Peers.
+5. Verify the BGP Local AS functionality with allowas-in in between iBGP Peers.
+6. Verify that BGP Local AS functionality by performing shut/ noshut on the interfaces in between BGP neighbors.
+7. Verify that BGP Local AS functionality by restarting BGP,Zebra and FRR services and
+ further restarting clear BGP * and shutdown BGP neighbor.
+8. Verify the BGP Local AS functionality with different AS configurations.
+9. Verify the BGP Local AS functionality with R3& R4 with different AS configurations.
+"""
+
+import os
+import sys
+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/"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib.topogen import Topogen, get_topogen
+from lib.topotest import version_cmp
+
+from lib.common_config import (
+ start_topology,
+ write_test_header,
+ create_static_routes,
+ write_test_footer,
+ reset_config_on_routers,
+ verify_rib,
+ step,
+ get_frr_ipv6_linklocal,
+ check_address_types,
+ check_router_status,
+ create_static_routes,
+ verify_fib_routes,
+ create_route_maps,
+ kill_router_daemons,
+ start_router_daemons,
+ shutdown_bringup_interface,
+)
+
+from lib.topolog import logger
+from lib.bgp import (
+ verify_bgp_convergence,
+ clear_bgp_and_verify,
+ verify_bgp_rib,
+ modify_as_number,
+ create_router_bgp,
+ verify_bgp_advertised_routes_from_neighbor,
+ verify_graceful_restart,
+ verify_r_bit,
+)
+from lib.topojson import build_config_from_json
+
+pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
+
+# Global variables
+NETWORK = {"ipv4": "10.1.1.0/32", "ipv6": "10:1::1:0/128"}
+NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"}
+NEXT_HOP_IP_GR = {"ipv4": "10.0.0.5", "ipv6": "fd00:0:0:1::2/64"}
+NEXT_HOP_IP_1 = {"ipv4": "10.0.0.101", "ipv6": "fd00::1"}
+NEXT_HOP_IP_2 = {"ipv4": "10.0.0.102", "ipv6": "fd00::2"}
+
+BGP_CONVERGENCE = False
+PREFERRED_NEXT_HOP = "link_local"
+KEEPALIVETIMER = 1
+HOLDDOWNTIMER = 3
+
+
+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...
+ json_file = "{}/bgp_local_asn_topo1.json".format(CWD)
+ tgen = Topogen(json_file, mod.__name__)
+ global topo
+ topo = tgen.json_topo
+ # ... and here it calls Mininet initialization functions.
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start daemons 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)
+
+
+##########################################################################################################
+#
+# Local APIs
+#
+##########################################################################################################
+
+
+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)
+
+ result = clear_bgp_and_verify(tgen, topo, dut)
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+ 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"]["{}".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
+
+
+##########################################################################################################
+#
+# Testcases
+#
+##########################################################################################################
+
+
+def test_verify_bgp_local_as_in_EBGP_p0(request):
+ """
+ Verify the BGP Local AS functionality by adding no-prepend and
+ replace-as command in between eBGP Peers.
+ """
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ step("Base config is done as part of JSON")
+ step("Configure local-as at R3 towards R4.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ for dut, asn, neighbor in zip(["r2", "r4"], ["200", "400"], ["r3", "r3"]):
+ input_dict_r2_r4 = {
+ dut: {
+ "bgp": {
+ "local_as": asn,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ dut: {"local_asn": {"remote_as": "110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r2_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ # configure static routes
+ step("Done in base config: Advertise prefix 10.1.1.0/32 from Router-1(AS-100).")
+ step(
+ "Done in base config: Advertise an ipv6 prefix 10:1::1:0/128 from Router-1(AS-100)."
+ )
+ step("Verify that Static routes are redistributed in BGP process")
+
+ dut = "r1"
+ protocol = "bgp"
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ input_static_r1 = {
+ "r1": {
+ "static_routes": [
+ {"network": NETWORK[addr_type], "next_hop": NEXT_HOP_IP[addr_type]}
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_static_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("configure redistribute static in Router BGP in R1")
+
+ input_static_redist_r1 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_static_redist_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify that Static routes are redistributed in BGP process")
+ for addr_type in ADDR_TYPES:
+ input_static_verify_r1 = {
+ "r1": {"static_routes": [{"network": NETWORK[addr_type]}]}
+ }
+
+ result = verify_rib(tgen, addr_type, "r1", input_static_verify_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut in ["r3", "r4"]:
+ result = verify_rib(tgen, addr_type, dut, input_static_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut, input_routes in zip(["r1"], [input_static_r1]):
+ result = verify_rib(tgen, addr_type, dut, input_routes)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that AS-110 is got added in the AS list 110 200 100 by following"
+ "commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "110 200 100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend at R3 towards R4 & R2.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "110",
+ "no_prepend": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step("Verify advertised routes to R4 at R3")
+ expected_routes = {
+ "ipv4": [
+ {"network": "10.1.1.0/32", "nexthop": ""},
+ ],
+ "ipv6": [
+ {"network": "10:1::1:0/128", "nexthop": ""},
+ ],
+ }
+ result = verify_bgp_advertised_routes_from_neighbor(
+ tgen, topo, dut="r3", peer="r4", expected_routes=expected_routes
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ dut = "r3"
+ aspath = "200 100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend and replace-as at R3 towards R4 & R2.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "110",
+ "no_prepend": True,
+ "replace_as": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ dut = "r4"
+ aspath = "110 200 100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_verify_bgp_local_as_in_EBGP_4B_AS_mid_2B_AS_p0(request):
+ """
+ Verify the BGP Local AS functionality by configuring 4 Byte AS
+ at R3 and 2 Byte AS at R2 & R4 in between eBGP Peers.
+ """
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ step("Base config is done as part of JSON")
+ step("Configure local-as at R3 towards R4.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "12000110"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ for dut, asn, neighbor in zip(["r2", "r4"], ["200", "400"], ["r3", "r3"]):
+ input_dict_r2_r4 = {
+ dut: {
+ "bgp": {
+ "local_as": asn,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ dut: {
+ "local_asn": {
+ "remote_as": "12000110"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r2_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ # configure static routes
+ step("Done in base config: Advertise prefix 10.1.1.0/32 from Router-1(AS-100).")
+ step(
+ "Done in base config: Advertise an ipv6 prefix 10:1::1:0/128 from Router-1(AS-100)."
+ )
+ step("Verify that Static routes are redistributed in BGP process")
+
+ dut = "r1"
+ protocol = "bgp"
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ input_static_r1 = {
+ "r1": {
+ "static_routes": [
+ {"network": NETWORK[addr_type], "next_hop": NEXT_HOP_IP[addr_type]}
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_static_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("configure redistribute static in Router BGP in R1")
+
+ input_static_redist_r1 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_static_redist_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify that Static routes are redistributed in BGP process")
+ for addr_type in ADDR_TYPES:
+ input_static_verify_r1 = {
+ "r1": {"static_routes": [{"network": NETWORK[addr_type]}]}
+ }
+
+ result = verify_rib(tgen, addr_type, "r1", input_static_verify_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut in ["r3", "r4"]:
+ result = verify_rib(tgen, addr_type, dut, input_static_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut, input_routes in zip(["r1"], [input_static_r1]):
+ result = verify_rib(tgen, addr_type, dut, input_routes)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that AS-12000110 is got added in the AS list 12000110 200 100 by following"
+ "commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "12000110 200 100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend at R3 towards R4 & R2.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "12000110",
+ "no_prepend": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step("Verify advertised routes to R4 at R3")
+ expected_routes = {
+ "ipv4": [
+ {"network": "10.1.1.0/32", "nexthop": ""},
+ ],
+ "ipv6": [
+ {"network": "10:1::1:0/128", "nexthop": ""},
+ ],
+ }
+ result = verify_bgp_advertised_routes_from_neighbor(
+ tgen, topo, dut="r3", peer="r4", expected_routes=expected_routes
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ dut = "r3"
+ aspath = "200 100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend and replace-as at R3 towards R4 & R2.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "12000110",
+ "no_prepend": True,
+ "replace_as": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ dut = "r4"
+ aspath = "12000110 200 100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_verify_bgp_local_as_GR_EBGP_p0(request):
+ """
+ Verify that BGP Local AS functionality by performing graceful restart in between eBGP Peers.
+ """
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ step("Configure basic BGP Peerings between R1,R2,R3 and R4")
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ input_dict_static_route = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": NEXT_HOP_IP_GR[addr_type],
+ }
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_static_route)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("configure redistribute static in Router BGP in R1")
+ input_dict_static_route_redist = {
+ "r1": {
+ "bgp": [
+ {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_static_route_redist)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ step("Verify IPv4 and IPv6 static routes received on R1")
+ result = verify_rib(tgen, addr_type, "r1", input_dict_static_route)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_dict_static_route)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ result = verify_fib_routes(tgen, addr_type, "r1", input_dict_static_route)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as at R3 towards R2.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r3_to_r2 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3_to_r2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as at R3 towards R4.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r3_to_r4 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3_to_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure remote-as at R2 towards R3.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r2_to_r3 = {
+ "r2": {
+ "bgp": [
+ {
+ "local_as": "200",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2": {
+ "local_asn": {"remote_as": "110"}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r2_to_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure remote-as at R4 towards R3.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r4_to_r3 = {
+ "r4": {
+ "bgp": [
+ {
+ "local_as": "400",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r4": {
+ "local_asn": {"remote_as": "110"}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r4_to_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step("Verify IPv4 and IPv6 static routes received on R3 & R4")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r1": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": NEXT_HOP_IP_GR[addr_type],
+ }
+ ]
+ }
+ }
+ for dut in ["r3", "r4"]:
+ result = verify_fib_routes(tgen, addr_type, dut, static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(tgen, addr_type, dut, static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that AS-110 is got added in the AS list 110 200 100 by following "
+ " commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "110 200 100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ """
+ GR Steps : Helper BGP router R2, mark and unmark IPV4 routes
+ as stale as the restarting router R3 come up within the restart time
+ """
+ # Create route-map to prefer global next-hop
+ input_dict = {
+ "r2": {
+ "route_maps": {
+ "rmap_global": [
+ {"action": "permit", "set": {"ipv6": {"nexthop": "prefer-global"}}}
+ ]
+ }
+ },
+ "r3": {
+ "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_neigh_rm = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2": {
+ "route_maps": [
+ {
+ "name": "rmap_global",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "r3": {
+ "bgp": {
+ "address_family": {
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [
+ {
+ "name": "rmap_global",
+ "direction": "in",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_neigh_rm)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ # Configure graceful-restart
+ input_dict = {
+ "r2": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2": {
+ "graceful-restart-helper": True,
+ "local_asn": {"remote_as": "110"},
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2": {
+ "graceful-restart-helper": True,
+ "local_asn": {"remote_as": "110"},
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ },
+ "r3": {
+ "bgp": {
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r2": {"dest_link": {"r3": {"graceful-restart": True}}}
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r2": {"dest_link": {"r3": {"graceful-restart": True}}}
+ }
+ }
+ },
+ }
+ }
+ },
+ }
+
+ configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r3", peer="r2")
+ for addr_type in ADDR_TYPES:
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r3", peer="r2"
+ )
+ assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result)
+
+ # Verifying BGP RIB routes
+ dut = "r2"
+ peer = "r3"
+ 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 ["r3"]}
+ 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] : R3 goes for reload ")
+
+ kill_router_daemons(tgen, "r3", ["bgpd"])
+
+ logger.info(
+ "[Phase 3] : R3 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 5] : R3 is about to come up now ")
+ start_router_daemons(tgen, "r3", ["bgpd"])
+
+ logger.info("[Phase 5] : R3 is UP Now ! ")
+
+ for addr_type in ADDR_TYPES:
+ result = verify_bgp_convergence(tgen, topo)
+ assert (
+ result is True
+ ), "BGP Convergence after BGPd restart" " :Failed \n Error:{}".format(result)
+
+ # Verifying GR stats
+ result = verify_graceful_restart(
+ tgen, topo, addr_type, input_dict, dut="r3", 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="r3")
+ 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
+ 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)
+
+ step("Configure local-as with no-prepend at R3 towards R2.")
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_r3_to_r2 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "110",
+ "no_prepend": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_no_prep_r3_to_r2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend at R3 towards R4.")
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_r3_to_r4 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "110",
+ "no_prepend": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_no_prep_r3_to_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ dut = "r3"
+ aspath = "200 100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r2": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend and replace-as at R3 towards R2")
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_rep_as_r3_to_r2 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "110",
+ "no_prepend": True,
+ "replace_as": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_no_prep_rep_as_r3_to_r2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend and replace-as at R3 towards R4")
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_rep_as_r3_to_r4 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "110",
+ "no_prepend": True,
+ "replace_as": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_no_prep_rep_as_r3_to_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ dut = "r4"
+ aspath = "110 200 100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_verify_bgp_local_as_in_EBGP_aspath_p0(request):
+ """
+ Verify the BGP Local AS functionality by adding another AS & by same AS with AS-Prepend command in between eBGP Peers.
+ """
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ step("Configure basic BGP Peerings between R1,R2,R3 and R4")
+ step("Configure local-as at R3 towards R4.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ for dut, asn, neighbor in zip(["r2", "r4"], ["200", "400"], ["r3", "r3"]):
+ input_dict_r2_r4 = {
+ dut: {
+ "bgp": {
+ "local_as": asn,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ dut: {"local_asn": {"remote_as": "110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r2_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ # configure static routes
+ step("Done in base config: Advertise prefix 10.1.1.0/32 from Router-1(AS-100).")
+ step(
+ "Done in base config: Advertise an ipv6 prefix 10:1::1:0/128 from Router-1(AS-100)."
+ )
+ step("Verify that Static routes are redistributed in BGP process")
+
+ dut = "r1"
+ protocol = "bgp"
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ input_static_r1 = {
+ "r1": {
+ "static_routes": [
+ {"network": NETWORK[addr_type], "next_hop": NEXT_HOP_IP[addr_type]}
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_static_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("configure redistribute static in Router BGP in R1")
+
+ input_static_redist_r1 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_static_redist_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify that Static routes are redistributed in BGP process")
+ for addr_type in ADDR_TYPES:
+ input_static_verify_r1 = {
+ "r1": {"static_routes": [{"network": NETWORK[addr_type]}]}
+ }
+
+ result = verify_rib(tgen, addr_type, "r1", input_static_verify_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut in ["r3", "r4"]:
+ result = verify_rib(tgen, addr_type, dut, input_static_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut, input_routes in zip(["r1"], [input_static_r1]):
+ result = verify_rib(tgen, addr_type, dut, input_routes)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that AS-110 is got added in the AS list 110 200 100 by following"
+ "commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "110 200 100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend at R3 towards R4 & R2.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "110",
+ "no_prepend": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step("Verify advertised routes to R4 at R3")
+ expected_routes = {
+ "ipv4": [
+ {"network": "10.1.1.0/32", "nexthop": ""},
+ ],
+ "ipv6": [
+ {"network": "10:1::1:0/128", "nexthop": ""},
+ ],
+ }
+ result = verify_bgp_advertised_routes_from_neighbor(
+ tgen, topo, dut="r3", peer="r4", expected_routes=expected_routes
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ dut = "r3"
+ aspath = "200 100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure a route-map on R3 to prepend AS 2 times.")
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "r3": {
+ "route_maps": {
+ "ASP_{}".format(addr_type): [
+ {
+ "action": "permit",
+ "set": {
+ "path": {"as_num": "1000 1000", "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 route map in out direction on R4")
+ # Configure neighbor for route map
+ input_dict_7 = {
+ "r3": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [
+ {
+ "name": "ASP_{}".format(
+ addr_type
+ ),
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_7)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend and replace-as at R3 towards R4 & R2.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "110",
+ "no_prepend": True,
+ "replace_as": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step(
+ "Verify that AS-300 is got replaced with 200 in the AS list 110 1000 1000 200 100 by following"
+ "commands at R3 router."
+ )
+ dut = "r4"
+ aspath = "110 1000 1000 200 100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ write_test_footer(tc_name)
+
+
+def test_verify_bgp_local_as_in_iBGP_p0(request):
+ """
+ Verify the BGP Local AS functionality by adding no-prepend and replace-as command in between iBGP Peers.
+ """
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ step("Modify AS Number for R3")
+ input_dict_modify_as_number = {"r3": {"bgp": {"local_as": 200}}}
+ result = modify_as_number(tgen, topo, input_dict_modify_as_number)
+
+ step("Base config is done as part of JSON")
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ input_dict_static_route = {
+ "r1": {
+ "static_routes": [
+ {"network": NETWORK[addr_type], "next_hop": NEXT_HOP_IP[addr_type]}
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_static_route)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("configure redistribute static in Router BGP in R1")
+ input_dict_static_route_redist = {
+ "r1": {
+ "bgp": [
+ {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_static_route_redist)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify IPv4 and IPv6 static routes received on R1")
+ result = verify_rib(tgen, addr_type, "r1", input_dict_static_route)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_dict_static_route)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ result = verify_fib_routes(tgen, addr_type, "r1", input_dict_static_route)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as at R3 towards R4.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r3_to_r4 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "200",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3_to_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure remote-as at R4 towards R3.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r4_to_r3 = {
+ "r4": {
+ "bgp": [
+ {
+ "local_as": "400",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r4": {
+ "local_asn": {"remote_as": "110"}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r4_to_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure remote-as at R2 towards R3.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r2_to_r3 = {
+ "r2": {
+ "bgp": [
+ {
+ "local_as": "200",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2": {
+ "next_hop_self": True,
+ "local_asn": {
+ "remote_as": "200",
+ },
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r2_to_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step("Verify IPv4 and IPv6 static routes received on R3 & R4")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r1": {
+ "static_routes": [
+ {"network": NETWORK[addr_type], "next_hop": NEXT_HOP_IP[addr_type]}
+ ]
+ }
+ }
+ for dut in ["r3", "r4"]:
+ result = verify_fib_routes(tgen, addr_type, dut, static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(tgen, addr_type, dut, static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that AS-110 is got added in the AS list 110 200 100 by following "
+ " commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ dut = "r4"
+ aspath = "110 200 100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend at R3 towards R4.")
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_r3_to_r4 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "200",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "110",
+ "no_prepend": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_no_prep_r3_to_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ dut = "r3"
+ aspath = "100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend and replace-as at R3 towards R4")
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_rep_as_r3_to_r4 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "200",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "110",
+ "no_prepend": True,
+ "replace_as": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_no_prep_rep_as_r3_to_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ dut = "r4"
+ aspath = "110 100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_verify_bgp_local_as_allow_as_in_iBGP_p0(request):
+ """
+ Verify the BGP Local AS functionality with allowas-in in between iBGP Peers.
+ """
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ step("Modidy AS Number for R4")
+ input_dict_modify_as_number = {"r4": {"bgp": {"local_as": 100}}}
+ result = modify_as_number(tgen, topo, input_dict_modify_as_number)
+
+ step("Base config is done as part of JSON")
+ dut = "r1"
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ input_dict_static_route = {
+ "r1": {
+ "static_routes": [
+ {"network": NETWORK[addr_type], "next_hop": NEXT_HOP_IP[addr_type]}
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_static_route)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("configure redistribute static in Router BGP in R1")
+ input_dict_static_route_redist = {
+ "r1": {
+ "bgp": [
+ {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_static_route_redist)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify IPv4 and IPv6 static routes received on R1")
+ result = verify_rib(tgen, addr_type, "r1", input_dict_static_route)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+ result = verify_bgp_rib(tgen, addr_type, "r1", input_dict_static_route)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ result = verify_fib_routes(tgen, addr_type, "r1", input_dict_static_route)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure allow-as at R4")
+ for addr_type in ADDR_TYPES:
+ allow_as_config_r4 = {
+ "r4": {
+ "bgp": [
+ {
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r4": {
+ "allowas-in": {
+ "number_occurences": 1
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ ]
+ }
+ }
+
+ step(
+ "Configuring allow-as for {} address-family on router R4 ".format(addr_type)
+ )
+ result = create_router_bgp(tgen, topo, allow_as_config_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ # now modify the as in r4 and reconfig bgp in r3 with new remote as.
+ topo1 = deepcopy(topo)
+ topo1["routers"]["r4"]["bgp"]["local_as"] = "100"
+
+ delete_bgp = {"r3": {"bgp": {"delete": True}}}
+ result = create_router_bgp(tgen, topo1, delete_bgp)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+ build_config_from_json(tgen, topo1, save_bkup=False)
+
+ step("Configure local-as at R3 towards R2.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r3_to_r2 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo1, input_dict_r3_to_r2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as at R3 towards R4.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r3_to_r4 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo1, input_dict_r3_to_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure remote-as at R2 towards R3.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r2_to_r3 = {
+ "r2": {
+ "bgp": [
+ {
+ "local_as": "200",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2": {
+ "local_asn": {"remote_as": "110"}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo1, input_dict_r2_to_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure remote-as at R4 towards R3.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r4_to_r3 = {
+ "r4": {
+ "bgp": [
+ {
+ "local_as": "100",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r4": {
+ "local_asn": {"remote_as": "110"}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo1, input_dict_r4_to_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo1)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step("Verify IPv4 and IPv6 static routes received on R3 & R4")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r1": {
+ "static_routes": [
+ {"network": NETWORK[addr_type], "next_hop": NEXT_HOP_IP[addr_type]}
+ ]
+ }
+ }
+ for dut in ["r3", "r4"]:
+ result = verify_fib_routes(tgen, addr_type, dut, static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(tgen, addr_type, dut, static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that AS-110 is got added in the AS list 110 200 100 by following "
+ " commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "110 200 100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend at R3 towards R2.")
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_r3_to_r2 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "110",
+ "no_prepend": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo1, input_dict_no_prep_r3_to_r2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend at R3 towards R4.")
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_r3_to_r4 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "110",
+ "no_prepend": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo1, input_dict_no_prep_r3_to_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo1)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ dut = "r3"
+ aspath = "200 100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r2": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend and replace-as at R3 towards R2")
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_rep_as_r3_to_r2 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "110",
+ "no_prepend": True,
+ "replace_as": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo1, input_dict_no_prep_rep_as_r3_to_r2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend and replace-as at R3 towards R4")
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_rep_as_r3_to_r4 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "110",
+ "no_prepend": True,
+ "replace_as": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo1, input_dict_no_prep_rep_as_r3_to_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo1)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ dut = "r4"
+ aspath = "110 200 100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_verify_bgp_local_as_in_EBGP_port_reset_p0(request):
+ """
+ Verify that BGP Local AS functionality by performing shut/ noshut on the interfaces in between BGP neighbors.
+ """
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ step("Base config is done as part of JSON")
+ step("Configure local-as at R3 towards R4.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ for dut, asn, neighbor in zip(["r2", "r4"], ["200", "400"], ["r3", "r3"]):
+ input_dict_r2_r4 = {
+ dut: {
+ "bgp": {
+ "local_as": asn,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ dut: {"local_asn": {"remote_as": "110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r2_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ # configure static routes
+ step("Done in base config: Advertise prefix 10.1.1.0/32 from Router-1(AS-100).")
+ step(
+ "Done in base config: Advertise an ipv6 prefix 10:1::1:0/128 from Router-1(AS-100)."
+ )
+ step("Verify that Static routes are redistributed in BGP process")
+ dut = "r1"
+ protocol = "bgp"
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ input_static_r1 = {
+ "r1": {
+ "static_routes": [
+ {"network": NETWORK[addr_type], "next_hop": NEXT_HOP_IP[addr_type]}
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_static_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("configure redistribute static in Router BGP in R1")
+ input_static_redist_r1 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_static_redist_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify that Static routes are redistributed in BGP process")
+ for addr_type in ADDR_TYPES:
+ input_static_verify_r1 = {
+ "r1": {"static_routes": [{"network": NETWORK[addr_type]}]}
+ }
+
+ result = verify_rib(tgen, addr_type, "r1", input_static_verify_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut in ["r3", "r4"]:
+ result = verify_rib(tgen, addr_type, dut, input_static_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut, input_routes in zip(["r1"], [input_static_r1]):
+ result = verify_rib(tgen, addr_type, dut, input_routes)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Api call to modfiy BGP timers at R3")
+ for addr_type in ADDR_TYPES:
+ input_dict_r3_timers = {
+ "r3": {
+ "bgp": {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "keepalivetimer": KEEPALIVETIMER,
+ "holddowntimer": HOLDDOWNTIMER,
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3_timers)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that AS-110 is got added in the AS list 110 200 100 by following"
+ "commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "110 200 100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify advertised routes at R3 towards R4")
+ expected_routes = {
+ "ipv4": [
+ {"network": "10.1.1.0/32", "nexthop": ""},
+ ],
+ "ipv6": [
+ {"network": "10:1::1:0/128", "nexthop": ""},
+ ],
+ }
+ result = verify_bgp_advertised_routes_from_neighbor(
+ tgen, topo, dut="r3", peer="r4", expected_routes=expected_routes
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ for count in range(1, 1):
+ step("Iteration {}".format(count))
+ step("Shut down connecting interface between R3<<>>R4 on R3.")
+
+ intf1 = topo["routers"]["r3"]["links"]["r4"]["interface"]
+
+ interfaces = [intf1]
+ for intf in interfaces:
+ shutdown_bringup_interface(tgen, "r3", intf, False)
+
+ step(
+ "On R3, all BGP peering in respective vrf instances go down"
+ " when the interface is shut"
+ )
+
+ 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)
+ )
+
+ step("BGP neighborship is verified after restart of r3")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step(
+ "Verify that AS-110 is got added in the AS list 110 200 100 by following"
+ "commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "110 200 100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend at R3 towards R4 & R2.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "110",
+ "no_prepend": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ dut = "r3"
+ aspath = "200 100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend and replace-as at R3 towards R4 & R2.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "110",
+ "no_prepend": True,
+ "replace_as": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ dut = "r4"
+ aspath = "110 200 100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_verify_bgp_local_as_in_EBGP_negative2_p0(request):
+ """
+ Verify the BGP Local AS functionality with different AS configurations.
+ """
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ step("Base config is done as part of JSON")
+ step("Configure local-as at R3 towards R4.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ for dut, asn, neighbor in zip(["r2", "r4"], ["200", "400"], ["r3", "r3"]):
+ input_dict_r2_r4 = {
+ dut: {
+ "bgp": {
+ "local_as": asn,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ dut: {"local_asn": {"remote_as": "110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r2_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ # configure static routes
+ step("Done in base config: Advertise prefix 10.1.1.0/32 from Router-1(AS-100).")
+ step(
+ "Done in base config: Advertise an ipv6 prefix 10:1::1:0/128 from Router-1(AS-100)."
+ )
+ step("Verify that Static routes are redistributed in BGP process")
+
+ dut = "r1"
+ protocol = "bgp"
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ input_static_r1 = {
+ "r1": {
+ "static_routes": [
+ {"network": NETWORK[addr_type], "next_hop": NEXT_HOP_IP[addr_type]}
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_static_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("configure redistribute static in Router BGP in R1")
+
+ input_static_redist_r1 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_static_redist_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify that Static routes are redistributed in BGP process")
+ for addr_type in ADDR_TYPES:
+ input_static_verify_r1 = {
+ "r1": {"static_routes": [{"network": NETWORK[addr_type]}]}
+ }
+
+ result = verify_rib(tgen, addr_type, "r1", input_static_verify_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut in ["r3", "r4"]:
+ result = verify_rib(tgen, addr_type, dut, input_static_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut, input_routes in zip(["r1"], [input_static_r1]):
+ result = verify_rib(tgen, addr_type, dut, input_routes)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that AS-110 is got added in the AS list 110 200 100 by following"
+ "commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "110 200 100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend at R3 towards R4 & R2.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "110",
+ "no_prepend": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step("Verify advertised routes to R4 at R3")
+ expected_routes = {
+ "ipv4": [
+ {"network": "10.1.1.0/32", "nexthop": ""},
+ ],
+ "ipv6": [
+ {"network": "10:1::1:0/128", "nexthop": ""},
+ ],
+ }
+ result = verify_bgp_advertised_routes_from_neighbor(
+ tgen, topo, dut="r3", peer="r4", expected_routes=expected_routes
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Verify that AS-110 is not prepended in the AS list 110 200 100 by following"
+ "commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "200 100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend and replace-as at R3 towards R4 & R2.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "110",
+ "no_prepend": True,
+ "replace_as": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+ step("Verify that AS-300 is replaced with AS-110 at R3 router.")
+ dut = "r4"
+ aspath = "110 200 100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ # configure negative scenarios
+ step("Configure local-as at R3 towards R4.")
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "300",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "300"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ if "bgp" in topo["routers"]["r3"].keys():
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is not True, (
+ "Testcase {} :Failed \n "
+ "Expected Behaviour: Cannot have local-as same as BGP AS number \n "
+ "Error {}".format(tc_name, result)
+ )
+
+ step("Configure another local-as at R3 towards R4.")
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "110",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ if "bgp" in topo["routers"]["r3"].keys():
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is not True, (
+ "Testcase {} :Failed \n "
+ "Expected Behaviour: Cannot have local-as same as BGP AS number \n "
+ "Error {}".format(tc_name, result)
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_verify_bgp_local_as_in_EBGP_negative3_p0(request):
+ """
+ Verify the BGP Local AS functionality with R3& R4 with different AS configurations.
+ """
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ step("Configure basic BGP Peerings between R1,R2,R3 and R4")
+ step("Configure local-as at R3 towards R4.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ for dut, asn, neighbor in zip(["r2", "r4"], ["200", "400"], ["r3", "r3"]):
+ input_dict_r2_r4 = {
+ dut: {
+ "bgp": {
+ "local_as": asn,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ dut: {"local_asn": {"remote_as": "110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r2_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ # configure static routes
+ step("Done in base config: Advertise prefix 10.1.1.0/32 from Router-1(AS-100).")
+ step(
+ "Done in base config: Advertise an ipv6 prefix 10:1::1:0/128 from Router-1(AS-100)."
+ )
+ step("Verify that Static routes are redistributed in BGP process")
+
+ dut = "r1"
+ protocol = "bgp"
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ input_static_r1 = {
+ "r1": {
+ "static_routes": [
+ {"network": NETWORK[addr_type], "next_hop": NEXT_HOP_IP[addr_type]}
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_static_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("configure redistribute static in Router BGP in R1")
+
+ input_static_redist_r1 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_static_redist_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify that Static routes are redistributed in BGP process")
+ for addr_type in ADDR_TYPES:
+ input_static_verify_r1 = {
+ "r1": {"static_routes": [{"network": NETWORK[addr_type]}]}
+ }
+
+ result = verify_rib(tgen, addr_type, "r1", input_static_verify_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut in ["r3", "r4"]:
+ result = verify_rib(tgen, addr_type, dut, input_static_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut, input_routes in zip(["r1"], [input_static_r1]):
+ result = verify_rib(tgen, addr_type, dut, input_routes)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that AS-110 is got added in the AS list 110 200 100 by following"
+ "commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "110 200 100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ # Perform Negative scenarios
+ step("Configure another local-as at R3 towards R4.")
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "300",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "300"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ if "bgp" in topo["routers"]["r3"].keys():
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is not True, (
+ "Testcase {} :Failed \n "
+ "Expected Behaviour: Cannot have local-as same as BGP AS number \n "
+ "Error {}".format(tc_name, result)
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_verify_bgp_local_as_in_EBGP_restart_daemons_p0(request):
+ """
+ Verify that BGP Local AS functionality by restarting BGP,Zebra and FRR services and
+ further restarting clear BGP * and shutdown BGP neighbor.
+ """
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ step("Base config is done as part of JSON")
+ step("Configure local-as at R3 towards R4.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ for dut, asn, neighbor in zip(["r2", "r4"], ["200", "400"], ["r3", "r3"]):
+ input_dict_r2_r4 = {
+ dut: {
+ "bgp": {
+ "local_as": asn,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ dut: {"local_asn": {"remote_as": "110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r2_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ # configure static routes
+ step("Done in base config: Advertise prefix 10.1.1.0/32 from Router-1(AS-100).")
+ step(
+ "Done in base config: Advertise an ipv6 prefix 10:1::1:0/128 from Router-1(AS-100)."
+ )
+ step("Verify that Static routes are redistributed in BGP process")
+ dut = "r1"
+ protocol = "bgp"
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ input_static_r1 = {
+ "r1": {
+ "static_routes": [
+ {"network": NETWORK[addr_type], "next_hop": NEXT_HOP_IP[addr_type]}
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_static_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("configure redistribute static in Router BGP in R1")
+ input_static_redist_r1 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_static_redist_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify that Static routes are redistributed in BGP process")
+ for addr_type in ADDR_TYPES:
+ input_static_verify_r1 = {
+ "r1": {"static_routes": [{"network": NETWORK[addr_type]}]}
+ }
+
+ result = verify_rib(tgen, addr_type, "r1", input_static_verify_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut in ["r3", "r4"]:
+ result = verify_rib(tgen, addr_type, dut, input_static_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut, input_routes in zip(["r1"], [input_static_r1]):
+ result = verify_rib(tgen, addr_type, dut, input_routes)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that AS-110 is got added in the AS list 110 200 100 by following"
+ "commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "110 200 100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Kill BGPd daemon on R3.")
+ kill_router_daemons(tgen, "r3", ["bgpd"])
+
+ step("Bring up BGPd daemon on R3.")
+ start_router_daemons(tgen, "r3", ["bgpd"])
+
+ step(
+ "Verify that AS-110 is got added in the AS list 110 200 100 by following"
+ "commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "110 200 100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify advertised routes at R3 towards R4")
+ expected_routes = {
+ "ipv4": [
+ {"network": "10.1.1.0/32", "nexthop": ""},
+ ],
+ "ipv6": [
+ {"network": "10:1::1:0/128", "nexthop": ""},
+ ],
+ }
+ result = verify_bgp_advertised_routes_from_neighbor(
+ tgen, topo, dut="r3", peer="r4", expected_routes=expected_routes
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Configure local-as with no-prepend at R3 towards R4 & R2.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "110",
+ "no_prepend": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step(
+ "Verify that AS-110 is not prepended in the AS list 200 100 by following "
+ "commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "200 100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Kill BGPd daemon on R3.")
+ kill_router_daemons(tgen, "r3", ["bgpd"])
+
+ step("Bring up BGPd daemon on R3.")
+ start_router_daemons(tgen, "r3", ["bgpd"])
+
+ step(
+ "Verify that AS-110 is not prepended in the AS list 200 100 by following "
+ "commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "200 100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend and replace-as at R3 towards R4 & R2.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "110",
+ "no_prepend": True,
+ "replace_as": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step(
+ "Verified that AS-300 is got replaced with original AS-110 at R4 by following commands"
+ )
+ dut = "r4"
+ aspath = "110 200 100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verified that AS-300 is got replaced with original AS-110 at R4 by following commands"
+ )
+ dut = "r4"
+ aspath = "110 200 100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ 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_local_asn/test_bgp_local_asn_topo2.py b/tests/topotests/bgp_local_asn/test_bgp_local_asn_topo2.py
new file mode 100644
index 000000000..6f4dc1bef
--- /dev/null
+++ b/tests/topotests/bgp_local_asn/test_bgp_local_asn_topo2.py
@@ -0,0 +1,699 @@
+#!/usr/bin/env python3
+#
+# Copyright (c) 2022 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.
+#
+##########################################################################################################
+#
+# Testcases
+#
+##########################################################################################################
+##########################################################################################################
+#
+# 1.10.1.2. Verify the BGP Local AS functionality by configuring 4 Byte AS in between eBGP Peers.
+#
+# 1.10.1.4. Verify the BGP Local AS functionality by configuring Old AS(local as) in 2 bytes and New AS in 4 bytes in between eBGP Peers.
+#
+###############################################################################################################
+
+import os
+import sys
+import time
+import pytest
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib.topogen import Topogen, get_topogen
+from lib.topotest import version_cmp
+
+from lib.common_config import (
+ start_topology,
+ write_test_header,
+ create_static_routes,
+ write_test_footer,
+ reset_config_on_routers,
+ verify_rib,
+ step,
+ check_address_types,
+ check_router_status,
+ create_static_routes,
+)
+
+from lib.topolog import logger
+from lib.bgp import (
+ verify_bgp_convergence,
+ verify_bgp_rib,
+ create_router_bgp,
+ verify_bgp_advertised_routes_from_neighbor,
+)
+from lib.topojson import build_config_from_json
+
+pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
+
+# Global variables
+BGP_CONVERGENCE = False
+ADDR_TYPES = check_address_types()
+NETWORK = {"ipv4": "10.1.1.0/32", "ipv6": "10:1::1:0/128"}
+NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"}
+
+
+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...
+ json_file = "{}/bgp_local_asn_topo2.json".format(CWD)
+ tgen = Topogen(json_file, mod.__name__)
+ global topo
+ topo = tgen.json_topo
+ # ... and here it calls Mininet initialization functions.
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start daemons 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_verify_bgp_local_as_in_4_Byte_AS_EBGP_p0(request):
+ """
+ Verify the BGP Local AS functionality by configuring 4 Byte AS in between eBGP Peers.
+ """
+
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ step("Base config is done as part of JSON")
+ step("Configure local-as at R3 towards R4.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "12000300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "12000110"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ for dut, asn, neighbor in zip(
+ ["r2", "r4"], ["12000200", "12000400"], ["r3", "r3"]
+ ):
+ input_dict_r2_r4 = {
+ dut: {
+ "bgp": {
+ "local_as": asn,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ dut: {
+ "local_asn": {
+ "remote_as": "12000110"
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r2_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ # configure static routes
+ step(
+ "Done in base config: Advertise prefix 10.1.1.0/32 from Router-1(AS-12000100)."
+ )
+ step(
+ "Done in base config: Advertise an ipv6 prefix 10:1::1:0/128 from Router-1(AS-12000100)."
+ )
+ step("Verify that Static routes are redistributed in BGP process")
+
+ dut = "r1"
+ protocol = "bgp"
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ input_static_r1 = {
+ "r1": {
+ "static_routes": [
+ {"network": NETWORK[addr_type], "next_hop": NEXT_HOP_IP[addr_type]}
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_static_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("configure redistribute static in Router BGP in R1")
+
+ input_static_redist_r1 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_static_redist_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify that Static routes are redistributed in BGP process")
+ for addr_type in ADDR_TYPES:
+ input_static_verify_r1 = {
+ "r1": {"static_routes": [{"network": NETWORK[addr_type]}]}
+ }
+
+ result = verify_rib(tgen, addr_type, "r1", input_static_verify_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut in ["r2", "r3", "r4"]:
+ result = verify_rib(tgen, addr_type, dut, input_static_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that AS-12000110 is got added in the AS list 12000110 12000200 12000100 by following"
+ "commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "12000110 12000200 12000100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend at R3 towards R4 & R2.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "12000300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "12000110",
+ "no_prepend": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step("Verify advertised routes to R4 at R3")
+ expected_routes = {
+ "ipv4": [
+ {"network": "10.1.1.0/32", "nexthop": ""},
+ ],
+ "ipv6": [
+ {"network": "10:1::1:0/128", "nexthop": ""},
+ ],
+ }
+ result = verify_bgp_advertised_routes_from_neighbor(
+ tgen, topo, dut="r3", peer="r4", expected_routes=expected_routes
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ dut = "r3"
+ aspath = "12000200 12000100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend and replace-as at R3 towards R4 & R2.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "12000300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "12000110",
+ "no_prepend": True,
+ "replace_as": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ dut = "r4"
+ aspath = "12000110 12000200 12000100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_verify_bgp_local_as_in_old_AS2_new_AS4_EBGP_p0(request):
+ """
+ Verify the BGP Local AS functionality by configuring Old AS(local as) in
+ 2 bytes and New AS in 4 bytes in between eBGP Peers.
+ """
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ step("Base config is done as part of JSON")
+ step("Configure local-as at R3 towards R4.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "12000300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for addr_type in ADDR_TYPES:
+ for dut, asn, neighbor in zip(
+ ["r2", "r4"], ["12000200", "12000400"], ["r3", "r3"]
+ ):
+ input_dict_r2_r4 = {
+ dut: {
+ "bgp": {
+ "local_as": asn,
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ dut: {"local_asn": {"remote_as": "110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r2_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ # configure static routes
+ step(
+ "Done in base config: Advertise prefix 10.1.1.0/32 from Router-1(AS-12000100)."
+ )
+ step(
+ "Done in base config: Advertise an ipv6 prefix 10:1::1:0/128 from Router-1(AS-12000100)."
+ )
+ step("Verify that Static routes are redistributed in BGP process")
+
+ dut = "r1"
+ protocol = "bgp"
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ input_static_r1 = {
+ "r1": {
+ "static_routes": [
+ {"network": NETWORK[addr_type], "next_hop": NEXT_HOP_IP[addr_type]}
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_static_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("configure redistribute static in Router BGP in R1")
+
+ input_static_redist_r1 = {
+ "r1": {
+ "bgp": {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_static_redist_r1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Verify that Static routes are redistributed in BGP process")
+ for addr_type in ADDR_TYPES:
+ input_static_verify_r1 = {
+ "r1": {"static_routes": [{"network": NETWORK[addr_type]}]}
+ }
+
+ result = verify_rib(tgen, addr_type, "r1", input_static_verify_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut in ["r3", "r4"]:
+ result = verify_rib(tgen, addr_type, dut, input_static_r1)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for dut, input_routes in zip(["r1"], [input_static_r1]):
+ result = verify_rib(tgen, addr_type, dut, input_routes)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that AS-110 is got added in the AS list 110 12000200 12000100 by following"
+ "commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "110 12000200 12000100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend at R3 towards R4 & R2.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "12000300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "110",
+ "no_prepend": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step("Verify advertised routes to R4 at R3")
+ expected_routes = {
+ "ipv4": [
+ {"network": "10.1.1.0/32", "nexthop": ""},
+ ],
+ "ipv6": [
+ {"network": "10:1::1:0/128", "nexthop": ""},
+ ],
+ }
+ result = verify_bgp_advertised_routes_from_neighbor(
+ tgen, topo, dut="r3", peer="r4", expected_routes=expected_routes
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ dut = "r3"
+ aspath = "12000200 12000100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend and replace-as at R3 towards R4 & R2.")
+ for addr_type in ADDR_TYPES:
+ for neighbor in ["r2", "r4"]:
+ input_dict_r3 = {
+ "r3": {
+ "bgp": {
+ "local_as": "12000300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ neighbor: {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "110",
+ "no_prepend": True,
+ "replace_as": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ dut = "r4"
+ aspath = "110 12000200 12000100"
+ for addr_type in ADDR_TYPES:
+ input_static_r1 = {"r1": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r1, aspath=aspath)
+ 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_local_asn/test_bgp_local_asn_vrf_topo1.py b/tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo1.py
new file mode 100644
index 000000000..5e2503f81
--- /dev/null
+++ b/tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo1.py
@@ -0,0 +1,1108 @@
+#!/usr/bin/env python3
+#
+# Copyright (c) 2022 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.
+#
+
+"""
+1. Verify the BGP Local AS functionality by adding new AS when dynamically import routes
+ from default vrf to non-default vrf with route map by adding AS by as-prepend command.
+2. Verify the BGP Local AS functionality by adding new AS when dynamically import routes
+ from non-default vrf to default vrf and further advertised to eBGP peers.
+"""
+
+import os
+import sys
+import time
+import pytest
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib.topogen import Topogen, get_topogen
+from lib.topotest import version_cmp
+
+from lib.common_config import (
+ start_topology,
+ write_test_header,
+ create_static_routes,
+ write_test_footer,
+ reset_config_on_routers,
+ verify_rib,
+ step,
+ check_address_types,
+ check_router_status,
+ create_static_routes,
+ verify_fib_routes,
+ create_route_maps,
+)
+
+from lib.topolog import logger
+from lib.bgp import (
+ verify_bgp_convergence,
+ verify_bgp_rib,
+ create_router_bgp,
+)
+from lib.topojson import build_config_from_json
+
+pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
+
+# Global variables
+BGP_CONVERGENCE = False
+ADDR_TYPES = check_address_types()
+NETWORK = {"ipv4": "10.1.1.0/32", "ipv6": "10:1::1:0/128"}
+NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"}
+
+
+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...
+ json_file = "{}/bgp_local_asn_vrf_topo1.json".format(CWD)
+ tgen = Topogen(json_file, mod.__name__)
+ global topo
+ topo = tgen.json_topo
+ # ... and here it calls Mininet initialization functions.
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start daemons 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_verify_local_asn_ipv4_import_from_default_to_non_default_VRF_p0(request):
+ """
+ Verify the BGP Local AS functionality by adding new AS when dynamically import routes
+ from default vrf to non-default vrf with route map by adding AS by as-prepend command.
+ """
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ step("Base config is done as part of JSON")
+
+ # configure static routes
+ step("Advertise prefix 10.0.0.1/32 from Router-1(AS-100).")
+ step("Advertise an ipv6 prefix 10::1/128 from Router-1(AS-100).")
+ dut = "r2"
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ input_dict_static_route = {
+ "r2": {
+ "static_routes": [
+ {"network": NETWORK[addr_type], "next_hop": NEXT_HOP_IP[addr_type]}
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_static_route)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("configure redistribute static in Router BGP in R2")
+ input_dict_static_route_redist = {
+ "r2": {
+ "bgp": [
+ {
+ "address_family": {
+ addr_type: {
+ "unicast": {"redistribute": [{"redist_type": "static"}]}
+ }
+ }
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_static_route_redist)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure import vrf BLUE on R3 under IPv4 Address Family")
+ input_import_vrf_ipv4 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": 300,
+ "vrf": "BLUE",
+ "address_family": {
+ "ipv4": {"unicast": {"import": {"vrf": "default"}}},
+ "ipv6": {"unicast": {"import": {"vrf": "default"}}},
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_import_vrf_ipv4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify IPv4 and IPv6 static routes received on R2")
+ for addr_type in ADDR_TYPES:
+ input_dict_static_route = {
+ "r2": {
+ "static_routes": [
+ {"network": NETWORK[addr_type], "next_hop": NEXT_HOP_IP[addr_type]}
+ ]
+ }
+ }
+ result = verify_rib(tgen, addr_type, "r2", input_dict_static_route)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+ result = verify_bgp_rib(tgen, addr_type, "r2", input_dict_static_route)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ result = verify_fib_routes(tgen, addr_type, "r2", input_dict_static_route)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as at R3 towards R2.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r3_to_r2 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3_to_r2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as at R3 towards R4.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r3_to_r4 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "300",
+ "vrf": "BLUE",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3_to_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure remote-as at R2 towards R3.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r2_to_r3 = {
+ "r2": {
+ "bgp": [
+ {
+ "local_as": "200",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2": {
+ "local_asn": {"remote_as": "110"}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r2_to_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure remote-as at R4 towards R3.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r4_to_r3 = {
+ "r4": {
+ "bgp": [
+ {
+ "local_as": "400",
+ "vrf": "BLUE",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r4": {
+ "local_asn": {"remote_as": "110"}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r4_to_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step("Verify IPv4 and IPv6 static routes received on R3 VRF BLUE & R4 VRF BLUE")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE",
+ }
+ ]
+ }
+ }
+ for dut in ["r3", "r4"]:
+ result = verify_fib_routes(tgen, addr_type, dut, static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(tgen, addr_type, dut, static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that AS-110 is got added in the AS list 110 200 100 by following "
+ " commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "110 200"
+ for addr_type in ADDR_TYPES:
+ input_static_r2 = {
+ "r2": {"static_routes": [{"network": NETWORK[addr_type], "vrf": "BLUE"}]}
+ }
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r2, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure a route-map on R3 to prepend AS 2 times.")
+ for addr_type in ADDR_TYPES:
+ input_dict_4 = {
+ "r3": {
+ "route_maps": {
+ "ASP_{}".format(addr_type): [
+ {
+ "action": "permit",
+ "set": {
+ "path": {"as_num": "1000 1000", "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 route map in out direction on R4")
+ # Configure neighbor for route map
+ input_dict_7 = {
+ "r3": {
+ "bgp": {
+ "local_as": "300",
+ "vrf": "BLUE",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [
+ {
+ "name": "ASP_{}".format(
+ addr_type
+ ),
+ "direction": "out",
+ }
+ ]
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_7)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend at R3 towards R2.")
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_r3_to_r2 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "110",
+ "no_prepend": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_no_prep_r3_to_r2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend at R3 towards R4.")
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_r3_to_r4 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "300",
+ "vrf": "BLUE",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "110",
+ "no_prepend": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_no_prep_r3_to_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ dut = "r3"
+ aspath = "200"
+ for addr_type in ADDR_TYPES:
+ input_static_r2 = {
+ "r2": {"static_routes": [{"network": NETWORK[addr_type], "vrf": "BLUE"}]}
+ }
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r2, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend and replace-as at R3 towards R2")
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_rep_as_r3_to_r2 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "110",
+ "no_prepend": True,
+ "replace_as": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_no_prep_rep_as_r3_to_r2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend and replace-as at R3 towards R4")
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_rep_as_r3_to_r4 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "300",
+ "vrf": "BLUE",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "110",
+ "no_prepend": True,
+ "replace_as": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_no_prep_rep_as_r3_to_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ dut = "r4"
+ aspath = "110 1000 1000 200"
+ for addr_type in ADDR_TYPES:
+ input_static_r2 = {
+ "r2": {"static_routes": [{"network": NETWORK[addr_type], "vrf": "BLUE"}]}
+ }
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r2, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ write_test_footer(tc_name)
+
+
+def test_verify_local_asn_ipv4_import_from_non_default_to_default_VRF_p0(request):
+ """
+ Verify the BGP Local AS functionality by adding new AS when dynamically import routes
+ from non-default vrf to default vrf and further advertised to eBGP peers.
+ """
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ step("Resetting the config from JSON")
+ reset_config_on_routers(tgen)
+
+ step("Base config is done as part of JSON")
+ # configure static routes
+ step("Advertise prefix 10.0.0.1/32 from Router-1(AS-100).")
+ step("Advertise an ipv6 prefix 10::1/128 from Router-1(AS-100).")
+ dut = "r4"
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ input_dict_static_route = {
+ "r4": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE",
+ }
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_static_route)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("configure redistribute static in Router BGP in R4")
+ input_dict_static_route_redist = {
+ "r4": {
+ "bgp": {
+ "local_as": 400,
+ "vrf": "BLUE",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"},
+ {"redist_type": "connected"},
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"},
+ {"redist_type": "connected"},
+ ]
+ }
+ },
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_static_route_redist)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step(
+ "Configure import from BLUE vrf to default vrf on R3 under IPv4 Address Family"
+ )
+ input_import_vrf_ipv4 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": 300,
+ "vrf": "default",
+ "address_family": {
+ "ipv4": {"unicast": {"import": {"vrf": "BLUE"}}},
+ "ipv6": {"unicast": {"import": {"vrf": "BLUE"}}},
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_import_vrf_ipv4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify IPv4 and IPv6 static routes received on R3 VRF BLUE & R4 VRF BLUE")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r4": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE",
+ }
+ ]
+ }
+ }
+ for dut in ["r3", "r4"]:
+ result = verify_fib_routes(tgen, addr_type, dut, static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(tgen, addr_type, dut, static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as at R3 towards R2.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r3_to_r2 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3_to_r2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as at R3 towards R4.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r3_to_r4 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "300",
+ "vrf": "BLUE",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3_to_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure remote-as at R2 towards R3.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r2_to_r3 = {
+ "r2": {
+ "bgp": [
+ {
+ "local_as": "200",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2": {
+ "local_asn": {"remote_as": "110"}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r2_to_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure remote-as at R4 towards R3.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r4_to_r3 = {
+ "r4": {
+ "bgp": [
+ {
+ "local_as": "400",
+ "vrf": "BLUE",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r4": {
+ "local_asn": {"remote_as": "110"}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r4_to_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step("Verify IPv4 and IPv6 static routes received on R2")
+ for addr_type in ADDR_TYPES:
+ input_dict_static_route_from_r4 = {
+ "r4": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ }
+ ]
+ }
+ }
+ result = verify_rib(tgen, addr_type, "r2", input_dict_static_route_from_r4)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+ result = verify_bgp_rib(tgen, addr_type, "r2", input_dict_static_route_from_r4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ result = verify_fib_routes(
+ tgen, addr_type, "r2", input_dict_static_route_from_r4
+ )
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that AS-110 is got added in the AS list 110 400 by following "
+ " commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "110 400"
+ for addr_type in ADDR_TYPES:
+ input_static_r2 = {"r4": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r2, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend at R3 towards R2.")
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_r3_to_r2 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "110",
+ "no_prepend": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_no_prep_r3_to_r2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend at R3 towards R4.")
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_r3_to_r4 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "300",
+ "vrf": "BLUE",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "110",
+ "no_prepend": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_no_prep_r3_to_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+ dut = "r3"
+ aspath = "400"
+ for addr_type in ADDR_TYPES:
+ input_static_r2 = {"r4": {"static_routes": [{"network": NETWORK[addr_type]}]}}
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r2, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend and replace-as at R3 towards R2")
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_rep_as_r3_to_r2 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "300",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "110",
+ "no_prepend": True,
+ "replace_as": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_no_prep_rep_as_r3_to_r2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend and replace-as at R3 towards R4")
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_rep_as_r3_to_r4 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "300",
+ "vrf": "BLUE",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "110",
+ "no_prepend": True,
+ "replace_as": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_no_prep_rep_as_r3_to_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ dut = "r2"
+ aspath = "110 400"
+ for addr_type in ADDR_TYPES:
+ input_static_r2 = {
+ "r4": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type],
+ }
+ ]
+ }
+ }
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r2, aspath=aspath)
+ 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_local_asn/test_bgp_local_asn_vrf_topo2.py b/tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo2.py
new file mode 100644
index 000000000..5992e0655
--- /dev/null
+++ b/tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo2.py
@@ -0,0 +1,826 @@
+#!/usr/bin/env python3
+#
+# Copyright (c) 2022 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.
+#
+
+"""
+1. Verify the BGP Local AS functionality by adding new AS when leaking routes
+ from non-default VRF to non-default with route map by prefix lists.
+"""
+
+import os
+import sys
+import time
+import pytest
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib.topogen import Topogen, get_topogen
+from lib.topotest import version_cmp
+
+from lib.common_config import (
+ start_topology,
+ write_test_header,
+ create_static_routes,
+ write_test_footer,
+ reset_config_on_routers,
+ verify_rib,
+ step,
+ check_address_types,
+ check_router_status,
+ create_static_routes,
+ create_prefix_lists,
+ verify_fib_routes,
+ create_route_maps,
+)
+
+from lib.topolog import logger
+from lib.bgp import (
+ verify_bgp_convergence,
+ verify_bgp_rib,
+ create_router_bgp,
+)
+from lib.topojson import build_config_from_json
+
+pytestmark = [pytest.mark.bgpd, pytest.mark.staticd]
+
+# Global variables
+BGP_CONVERGENCE = False
+ADDR_TYPES = check_address_types()
+NETWORK = {"ipv4": "10.1.1.0/32", "ipv6": "10:1::1:0/128"}
+NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"}
+
+
+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...
+ json_file = "{}/bgp_local_asn_vrf_topo2.json".format(CWD)
+ tgen = Topogen(json_file, mod.__name__)
+ global topo
+ topo = tgen.json_topo
+ # ... and here it calls Mininet initialization functions.
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start daemons 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_verify_local_asn_ipv4_import_from_non_default_to_non_default_VRF_p0(request):
+ """
+ Verify the BGP Local AS functionality by adding new AS when leaking routes
+ from non-default VRF to non-default with route map by prefix lists.
+ """
+ tgen = get_topogen()
+ global BGP_CONVERGENCE
+ if BGP_CONVERGENCE != True:
+ pytest.skip("skipped because of BGP Convergence failure")
+
+ # test case name
+ tc_name = request.node.name
+ write_test_header(tc_name)
+ if tgen.routers_have_failure():
+ check_router_status(tgen)
+ reset_config_on_routers(tgen)
+
+ step("Base config is done as part of JSON")
+
+ # configure static routes
+ step("Advertise prefix 10.1.1.0/32 from Router-1(AS-100).")
+ step("Advertise an ipv6 prefix 10:1::1:0/128 from Router-1(AS-100).")
+ dut = "r2"
+ for addr_type in ADDR_TYPES:
+ # Enable static routes
+ input_dict_static_route = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "RED",
+ }
+ ]
+ }
+ }
+
+ logger.info("Configure static routes")
+ result = create_static_routes(tgen, input_dict_static_route)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("configure redistribute static in Router BGP in R2")
+ input_dict_static_route_redist = {
+ "r2": {
+ "bgp": {
+ "local_as": 200,
+ "vrf": "RED",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"},
+ {"redist_type": "connected"},
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"},
+ {"redist_type": "connected"},
+ ]
+ }
+ },
+ },
+ }
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_static_route_redist)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Configure import vrf BLUE from vrf RED on R3 under IPv4 Address Family")
+ input_import_vrf_ipv4 = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": 300,
+ "vrf": "BLUE",
+ "address_family": {
+ "ipv4": {"unicast": {"import": {"vrf": "RED"}}},
+ "ipv6": {"unicast": {"import": {"vrf": "RED"}}},
+ },
+ }
+ ]
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_import_vrf_ipv4)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result)
+
+ step("Verify IPv4 and IPv6 static routes received on R3 VRF BLUE & R4 VRF BLUE")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE",
+ }
+ ]
+ }
+ }
+ for dut in ["r3", "r4"]:
+ result = verify_fib_routes(tgen, addr_type, dut, static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+ result = verify_bgp_rib(tgen, addr_type, dut, static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as at R3 towards R2.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r3_to_r2 = {
+ "r3": {
+ "vrfs": [{"name": "RED", "id": "1"}],
+ "bgp": [
+ {
+ "local_as": "300",
+ "vrf": "RED",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ],
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3_to_r2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as at R3 towards R4.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r3_to_r4 = {
+ "r3": {
+ "vrfs": [{"name": "BLUE", "id": "1"}],
+ "bgp": [
+ {
+ "local_as": "300",
+ "vrf": "BLUE",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {"local_asn": {"local_as": "110"}}
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ],
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r3_to_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure remote-as at R2 towards R3.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r2_to_r3 = {
+ "r2": {
+ "vrfs": [{"name": "RED", "id": "1"}],
+ "bgp": [
+ {
+ "local_as": "200",
+ "vrf": "RED",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r2": {
+ "local_asn": {"remote_as": "110"}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ],
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r2_to_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure remote-as at R4 towards R3.")
+ for addr_type in ADDR_TYPES:
+ input_dict_r4_to_r3 = {
+ "r4": {
+ "vrfs": [{"name": "BLUE", "id": "1"}],
+ "bgp": [
+ {
+ "local_as": "400",
+ "vrf": "BLUE",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r3": {
+ "dest_link": {
+ "r4": {
+ "local_asn": {"remote_as": "110"}
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ],
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_r4_to_r3)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ step("Verify IPv4 and IPv6 static routes received on R3 VRF BLUE & R4 VRF BLUE")
+ for addr_type in ADDR_TYPES:
+ static_routes_input = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK[addr_type],
+ "next_hop": NEXT_HOP_IP[addr_type],
+ "vrf": "BLUE",
+ }
+ ]
+ }
+ }
+ for dut in ["r3", "r4"]:
+ result = verify_fib_routes(tgen, addr_type, dut, static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_bgp_rib(tgen, addr_type, dut, static_routes_input)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step(
+ "Verify that AS-110 is got added in the AS list 110 200 100 by following "
+ " commands at R3 router."
+ )
+ dut = "r3"
+ aspath = "110 200"
+ for addr_type in ADDR_TYPES:
+ input_static_r2 = {
+ "r2": {"static_routes": [{"network": NETWORK[addr_type], "vrf": "BLUE"}]}
+ }
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r2, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ # configure the prefix-list and route-maps.
+ for adt in ADDR_TYPES:
+ # Create Static routes
+ input_dict_rm1 = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": NETWORK[adt],
+ "no_of_ip": 1,
+ "next_hop": NEXT_HOP_IP[adt],
+ "vrf": "RED",
+ }
+ ]
+ }
+ }
+
+ result = create_static_routes(tgen, input_dict_rm1)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ # Api call to redistribute static routes
+ input_dict_rm_rd = {
+ "r2": {
+ "bgp": {
+ "local_as": 200,
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"},
+ {"redist_type": "connected"},
+ ]
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "redistribute": [
+ {"redist_type": "static"},
+ {"redist_type": "connected"},
+ ]
+ }
+ },
+ },
+ }
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_rm_rd)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ input_dict_rm_pl = {
+ "r3": {
+ "prefix_lists": {
+ "ipv4": {
+ "pf_list_1_ipv4": [
+ {
+ "seqid": 10,
+ "action": "permit",
+ "network": NETWORK["ipv4"],
+ }
+ ]
+ },
+ "ipv6": {
+ "pf_list_1_ipv6": [
+ {
+ "seqid": 100,
+ "action": "permit",
+ "network": NETWORK["ipv6"],
+ }
+ ]
+ },
+ }
+ }
+ }
+ result = create_prefix_lists(tgen, input_dict_rm_pl)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ # Create route map
+ for addr_type in ADDR_TYPES:
+ input_dict_rm_r3 = {
+ "r3": {
+ "route_maps": {
+ "rmap_match_tag_1_{}".format(addr_type): [
+ {
+ "action": "permit",
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_1_{}".format(addr_type)
+ }
+ },
+ }
+ ],
+ "rmap_match_tag_2_{}".format(addr_type): [
+ {
+ "action": "permit",
+ "match": {
+ addr_type: {
+ "prefix_lists": "pf_list_2_{}".format(addr_type)
+ }
+ },
+ }
+ ],
+ }
+ }
+ }
+ result = create_route_maps(tgen, input_dict_rm_r3)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ # Configure neighbor for route map
+ input_dict_conf_neighbor_rm = {
+ "r3": {
+ "bgp": [
+ {
+ "local_as": "300",
+ "vrf": "BLUE",
+ "address_family": {
+ "ipv4": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [
+ {
+ "name": "rmap_match_tag_1_ipv4",
+ "direction": "out",
+ },
+ {
+ "name": "rmap_match_tag_1_ipv4",
+ "direction": "out",
+ },
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ "ipv6": {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "route_maps": [
+ {
+ "name": "rmap_match_tag_1_ipv6",
+ "direction": "in",
+ },
+ {
+ "name": "rmap_match_tag_1_ipv6",
+ "direction": "out",
+ },
+ ]
+ }
+ }
+ }
+ }
+ }
+ },
+ },
+ }
+ ]
+ }
+ }
+
+ result = create_router_bgp(tgen, topo, input_dict_conf_neighbor_rm)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ for adt in ADDR_TYPES:
+ # Verifying RIB routes
+ dut = "r3"
+ input_dict_r2_rib = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK[adt]],
+ "no_of_ip": 1,
+ "next_hop": NEXT_HOP_IP[adt],
+ "vrf": "RED",
+ }
+ ]
+ }
+ }
+ result = verify_rib(tgen, adt, dut, input_dict_r2_rib)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ # Verifying RIB routes
+ dut = "r4"
+ input_dict_r2_rib = {
+ "r2": {
+ "static_routes": [
+ {
+ "network": [NETWORK[adt]],
+ "no_of_ip": 1,
+ "next_hop": NEXT_HOP_IP[adt],
+ "vrf": "BLUE",
+ }
+ ]
+ }
+ }
+ result = verify_rib(tgen, adt, dut, input_dict_r2_rib)
+ assert result is True, "Testcase {}: Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend at R3 towards R2.")
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_r3_to_r2 = {
+ "r3": {
+ "vrfs": [{"name": "RED", "id": "1"}],
+ "bgp": [
+ {
+ "local_as": "300",
+ "vrf": "RED",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "110",
+ "no_prepend": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ],
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_no_prep_r3_to_r2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend at R3 towards R4.")
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_r3_to_r4 = {
+ "r3": {
+ "vrfs": [{"name": "BLUE", "id": "1"}],
+ "bgp": [
+ {
+ "local_as": "300",
+ "vrf": "BLUE",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "110",
+ "no_prepend": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ],
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_no_prep_r3_to_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ dut = "r3"
+ aspath = "200"
+ for addr_type in ADDR_TYPES:
+ input_static_r2 = {
+ "r2": {"static_routes": [{"network": NETWORK[addr_type], "vrf": "BLUE"}]}
+ }
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r2, aspath=aspath)
+ assert result is True, "Testcase {} : Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend and replace-as at R3 towards R2")
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_rep_as_r3_to_r2 = {
+ "r3": {
+ "vrfs": [{"name": "RED", "id": "1"}],
+ "bgp": [
+ {
+ "local_as": "300",
+ "vrf": "RED",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r2": {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "110",
+ "no_prepend": True,
+ "replace_as": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ],
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_no_prep_rep_as_r3_to_r2)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("Configure local-as with no-prepend and replace-as at R3 towards R4")
+ for addr_type in ADDR_TYPES:
+ input_dict_no_prep_rep_as_r3_to_r4 = {
+ "r3": {
+ "vrfs": [{"name": "BLUE", "id": "1"}],
+ "bgp": [
+ {
+ "local_as": "300",
+ "vrf": "BLUE",
+ "address_family": {
+ addr_type: {
+ "unicast": {
+ "neighbor": {
+ "r4": {
+ "dest_link": {
+ "r3": {
+ "local_asn": {
+ "local_as": "110",
+ "no_prepend": True,
+ "replace_as": True,
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ }
+ ],
+ }
+ }
+ result = create_router_bgp(tgen, topo, input_dict_no_prep_rep_as_r3_to_r4)
+ assert result is True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("BGP neighborship is verified by following commands in R3 routers")
+ BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo)
+ assert BGP_CONVERGENCE is True, "BGP convergence :Failed \n Error: {}".format(
+ BGP_CONVERGENCE
+ )
+
+ dut = "r4"
+ aspath = "110 200"
+ for addr_type in ADDR_TYPES:
+ input_static_r2 = {
+ "r2": {"static_routes": [{"network": NETWORK[addr_type], "vrf": "BLUE"}]}
+ }
+ result = verify_bgp_rib(tgen, addr_type, dut, input_static_r2, aspath=aspath)
+ 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_max_med_on_startup/__init__.py b/tests/topotests/bgp_max_med_on_startup/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/bgp_max_med_on_startup/__init__.py
diff --git a/tests/topotests/bgp_max_med_on_startup/r1/bgpd.conf b/tests/topotests/bgp_max_med_on_startup/r1/bgpd.conf
new file mode 100644
index 000000000..41bf96344
--- /dev/null
+++ b/tests/topotests/bgp_max_med_on_startup/r1/bgpd.conf
@@ -0,0 +1,11 @@
+!
+router bgp 65001
+ bgp max-med on-startup 5 777
+ no bgp ebgp-requires-policy
+ neighbor 192.168.255.2 remote-as 65001
+ neighbor 192.168.255.2 timers 3 10
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+ !
+!
diff --git a/tests/topotests/bgp_max_med_on_startup/r1/zebra.conf b/tests/topotests/bgp_max_med_on_startup/r1/zebra.conf
new file mode 100644
index 000000000..7c2ed09b8
--- /dev/null
+++ b/tests/topotests/bgp_max_med_on_startup/r1/zebra.conf
@@ -0,0 +1,9 @@
+!
+interface lo
+ ip address 172.16.255.254/32
+!
+interface r1-eth0
+ ip address 192.168.255.1/30
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_max_med_on_startup/r2/bgpd.conf b/tests/topotests/bgp_max_med_on_startup/r2/bgpd.conf
new file mode 100644
index 000000000..187713d08
--- /dev/null
+++ b/tests/topotests/bgp_max_med_on_startup/r2/bgpd.conf
@@ -0,0 +1,7 @@
+!
+router bgp 65001
+ no bgp ebgp-requires-policy
+ neighbor 192.168.255.1 remote-as 65001
+ neighbor 192.168.255.1 timers 3 10
+ !
+!
diff --git a/tests/topotests/bgp_max_med_on_startup/r2/zebra.conf b/tests/topotests/bgp_max_med_on_startup/r2/zebra.conf
new file mode 100644
index 000000000..fd45c48d6
--- /dev/null
+++ b/tests/topotests/bgp_max_med_on_startup/r2/zebra.conf
@@ -0,0 +1,6 @@
+!
+interface r2-eth0
+ ip address 192.168.255.2/30
+!
+ip forwarding
+!
diff --git a/tests/topotests/bgp_max_med_on_startup/test_bgp_max_med_on_startup.py b/tests/topotests/bgp_max_med_on_startup/test_bgp_max_med_on_startup.py
new file mode 100644
index 000000000..a83d43310
--- /dev/null
+++ b/tests/topotests/bgp_max_med_on_startup/test_bgp_max_med_on_startup.py
@@ -0,0 +1,114 @@
+#!/usr/bin/env python
+
+#
+# test_bgp_max_med_on_startup.py
+#
+# Copyright (c) 2022 Rubicon Communications, LLC.
+#
+# 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 whether `bgp max-med on-startup (5-86400) [(0-4294967295)]` is working
+correctly.
+"""
+
+import os
+import sys
+import json
+import pytest
+import functools
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def build_topo(tgen):
+ for routern in range(1, 3):
+ tgen.add_router("r{}".format(routern))
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+
+def setup_module(mod):
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for i, (rname, router) in enumerate(router_list.items(), 1):
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_max_med_on_startup():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router1 = tgen.gears["r1"]
+ router2 = tgen.gears["r2"]
+
+ def _bgp_converge(router):
+ output = json.loads(router.vtysh_cmd("show ip bgp neighbor 192.168.255.1 json"))
+ expected = {"192.168.255.1": {"bgpState": "Established"}}
+ return topotest.json_cmp(output, expected)
+
+ def _bgp_has_routes(router, metric):
+ output = json.loads(
+ router.vtysh_cmd("show ip bgp neighbor 192.168.255.1 routes json")
+ )
+ expected = {"routes": {"172.16.255.254/32": [{"metric": metric}]}}
+ return topotest.json_cmp(output, expected)
+
+ # Check session is established
+ test_func = functools.partial(_bgp_converge, router2)
+ success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
+ assert result is None, "Failed bgp convergence on r2"
+
+ # Check metric has value of max-med
+ test_func = functools.partial(_bgp_has_routes, router2, 777)
+ success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
+ assert result is None, "r2 does not receive routes with metric 777"
+
+ # Check that when the max-med timer expires, metric is updated
+ test_func = functools.partial(_bgp_has_routes, router2, 0)
+ success, result = topotest.run_and_expect(test_func, None, count=16, wait=0.5)
+ assert result is None, "r2 does not receive routes with metric 0"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_prefix_list_topo1/test_prefix_lists.py b/tests/topotests/bgp_prefix_list_topo1/test_prefix_lists.py
index 2dc95cee2..5131a89ce 100644
--- a/tests/topotests/bgp_prefix_list_topo1/test_prefix_lists.py
+++ b/tests/topotests/bgp_prefix_list_topo1/test_prefix_lists.py
@@ -346,9 +346,12 @@ def test_ip_prefix_lists_out_permit(request):
result = verify_rib(
tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n Error: Routes still" " present in RIB".format(tc_name)
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
+ )
+
write_test_footer(tc_name)
@@ -444,9 +447,11 @@ def test_ip_prefix_lists_in_deny_and_permit_any(request):
result = verify_rib(
tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n Error: Routes still" " present in RIB".format(tc_name)
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
+ )
write_test_footer(tc_name)
@@ -644,9 +649,12 @@ def test_ip_prefix_lists_out_deny_and_permit_any(request):
result = verify_rib(
tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n Error: Routes still" " present in RIB".format(tc_name)
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
+ )
+
write_test_footer(tc_name)
@@ -778,9 +786,11 @@ def test_modify_prefix_lists_in_permit_to_deny(request):
result = verify_rib(
tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n Error: Routes still" " present in RIB".format(tc_name)
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
+ )
write_test_footer(tc_name)
@@ -882,9 +892,11 @@ def test_modify_prefix_lists_in_deny_to_permit(request):
result = verify_rib(
tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n Error: Routes still" " present in RIB".format(tc_name)
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
+ )
# Modify ip prefix list
input_dict_1 = {
@@ -1051,9 +1063,11 @@ def test_modify_prefix_lists_out_permit_to_deny(request):
result = verify_rib(
tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n Error: Routes still" " present in RIB".format(tc_name)
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
+ )
write_test_footer(tc_name)
@@ -1157,9 +1171,11 @@ def test_modify_prefix_lists_out_deny_to_permit(request):
result = verify_rib(
tgen, "ipv4", dut, input_dict, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n Error: Routes still" " present in RIB".format(tc_name)
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
+ )
# Modify ip prefix list
input_dict_1 = {
@@ -1324,9 +1340,11 @@ def test_ip_prefix_lists_implicit_deny(request):
result = verify_rib(
tgen, "ipv4", dut, input_dict_1, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n Error: Routes still" " present in RIB".format(tc_name)
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
+ )
write_test_footer(tc_name)
diff --git a/tests/topotests/bgp_route_map/test_route_map_topo1.py b/tests/topotests/bgp_route_map/test_route_map_topo1.py
index 655a3dc89..77bddbe33 100644
--- a/tests/topotests/bgp_route_map/test_route_map_topo1.py
+++ b/tests/topotests/bgp_route_map/test_route_map_topo1.py
@@ -444,12 +444,11 @@ def test_route_map_inbound_outbound_same_neighbor_p0(request):
result = verify_rib(
tgen, adt, dut, input_dict_2, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \nroutes are not present in rib \n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} BGP RIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info("Expected behaviour: {}".format(result))
# Verifying RIB routes
dut = "r4"
@@ -467,12 +466,11 @@ def test_route_map_inbound_outbound_same_neighbor_p0(request):
result = verify_rib(
tgen, adt, dut, input_dict, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \nroutes are not present in rib \n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info("Expected behaviour: {}".format(result))
write_test_footer(tc_name)
@@ -666,12 +664,11 @@ def test_route_map_with_action_values_combination_of_prefix_action_p0(
result = verify_rib(
tgen, adt, dut, input_dict_2, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \nRoutes are still present \n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info("Expected behaviour: {}".format(result))
else:
result = verify_rib(tgen, adt, dut, input_dict_2, protocol=protocol)
assert result is True, "Testcase {} : Failed \n Error: {}".format(
diff --git a/tests/topotests/bgp_route_map/test_route_map_topo2.py b/tests/topotests/bgp_route_map/test_route_map_topo2.py
index 4da7eeb2f..589482d6a 100644
--- a/tests/topotests/bgp_route_map/test_route_map_topo2.py
+++ b/tests/topotests/bgp_route_map/test_route_map_topo2.py
@@ -1022,12 +1022,11 @@ def test_modify_prefix_list_referenced_by_rmap_p0():
result = verify_rib(
tgen, addr_type, dut, input_dict, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \nroutes are not present \n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info("Expected behaviour: {}".format(result))
# Verifying RIB routes
dut = "r4"
@@ -1036,10 +1035,10 @@ def test_modify_prefix_list_referenced_by_rmap_p0():
result = verify_rib(
tgen, addr_type, dut, input_dict, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \nExpected behaviour: routes are not present \n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
write_test_footer(tc_name)
@@ -1293,12 +1292,11 @@ def test_remove_prefix_list_referenced_by_rmap_p0():
result = verify_rib(
tgen, addr_type, dut, input_dict, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \nroutes are not present \n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info("Expected behaviour: {}".format(result))
# Verifying RIB routes
dut = "r4"
@@ -1307,12 +1305,11 @@ def test_remove_prefix_list_referenced_by_rmap_p0():
result = verify_rib(
tgen, addr_type, dut, input_dict, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \nroutes are not present \n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info("Expected behaviour: {}".format(result))
write_test_footer(tc_name)
@@ -2139,12 +2136,11 @@ def test_add_remove_rmap_to_specific_neighbor_p0():
result = verify_rib(
tgen, addr_type, dut, input_dict, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \n Error Routes are still present: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info("Expected behaviour: {}".format(result))
# Remove applied rmap from neighbor
input_dict_4 = {
@@ -2553,12 +2549,11 @@ def test_rmap_without_match_and_set_clause_p0():
result = verify_rib(
tgen, addr_type, dut, input_dict, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \nroutes are not present \n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info("Expected behaviour: {}".format(result))
write_test_footer(tc_name)
# Uncomment next line for debugging
@@ -2801,12 +2796,11 @@ def test_set_localpref_weight_to_ebgp_and_med_to_ibgp_peers_p0():
input_dict_3_addr_type[addr_type],
expected=False,
)
- assert (
- result is not True
- ), "Testcase {} : Failed \nAttributes are not set \n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: BGP attributes should not be set in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info("Expected behaviour: {}".format(result))
# Verifying RIB routes
dut = "r5"
@@ -2835,12 +2829,11 @@ def test_set_localpref_weight_to_ebgp_and_med_to_ibgp_peers_p0():
input_dict_3_addr_type[addr_type],
expected=False,
)
- assert (
- result is not True
- ), "Testcase {} : Failed \nAttributes are not set \n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: BGP attributes should not be set in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info("Expected behaviour: {}".format(result))
write_test_footer(tc_name)
@@ -3644,12 +3637,11 @@ def test_create_rmap_match_prefix_list_to_deny_in_and_outbound_prefixes_p0():
result = verify_rib(
tgen, addr_type, dut, input_dict, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \nroutes are not present \n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info("Expected behaviour: {}".format(result))
# Verifying RIB routes
dut = "r4"
@@ -3658,12 +3650,11 @@ def test_create_rmap_match_prefix_list_to_deny_in_and_outbound_prefixes_p0():
result = verify_rib(
tgen, addr_type, dut, input_dict, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \nroutes are not present \n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info("Expected behaviour: {}".format(result))
write_test_footer(tc_name)
@@ -3963,12 +3954,11 @@ def test_create_rmap_to_match_tag_deny_outbound_prefixes_p0():
result = verify_rib(
tgen, addr_type, dut, input_dict, protocol=protocol, expected=False
)
- assert (
- result is not True
- ), "Testcase {} : Failed \nroutes are denied \n Error: {}".format(
- tc_name, result
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "Expected: Routes should not be present in {} FIB \n "
+ "Found: {}".format(tc_name, dut, result)
)
- logger.info("Expected behaviour: {}".format(result))
write_test_footer(tc_name)
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/zebra.conf
index 8defa0125..8ccf7a2a3 100644
--- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/zebra.conf
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/zebra.conf
@@ -27,7 +27,7 @@ segment-routing
srv6
locators
locator loc1
- prefix 2001:db8:1:1::/64
+ prefix 2001:db8:1:1::/64 func-bits 8
!
!
!
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/zebra.conf
index 51d9c9223..839454d8a 100644
--- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/zebra.conf
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/zebra.conf
@@ -27,7 +27,7 @@ segment-routing
srv6
locators
locator loc1
- prefix 2001:db8:2:2::/64
+ prefix 2001:db8:2:2::/64 func-bits 8
!
!
!
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/zebra.conf
index a43cec20e..a9319a6ae 100644
--- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/zebra.conf
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/zebra.conf
@@ -28,7 +28,7 @@ segment-routing
srv6
locators
locator loc1
- prefix 2001:db8:1:1::/64
+ prefix 2001:db8:1:1::/64 func-bits 8
!
!
!
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/zebra.conf
index 71ddedf6f..9e5fa0ac0 100644
--- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/zebra.conf
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/zebra.conf
@@ -27,7 +27,7 @@ segment-routing
srv6
locators
locator loc1
- prefix 2001:db8:2:2::/64
+ prefix 2001:db8:2:2::/64 func-bits 8
!
!
!
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce1/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce1/bgpd.conf
new file mode 100644
index 000000000..345979662
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce1/bgpd.conf
@@ -0,0 +1,8 @@
+frr defaults traditional
+!
+hostname ce1
+password zebra
+!
+log stdout notifications
+log commands
+log file bgpd.log
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce1/ip_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce1/ip_rib.json
new file mode 100644
index 000000000..1d33fee71
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce1/ip_rib.json
@@ -0,0 +1,58 @@
+{
+ "0.0.0.0/0": [
+ {
+ "prefix": "0.0.0.0/0",
+ "protocol": "static",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 1,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 73,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "ip": "192.168.1.1",
+ "afi": "ipv4",
+ "interfaceName": "eth0",
+ "active": true,
+ "weight": 1
+ }
+ ]
+ }
+ ],
+ "192.168.1.0/24": [
+ {
+ "prefix": "192.168.1.0/24",
+ "protocol": "connected",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth0",
+ "active": true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce1/ipv6_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce1/ipv6_rib.json
new file mode 100644
index 000000000..d19e31577
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce1/ipv6_rib.json
@@ -0,0 +1,58 @@
+{
+ "::/0": [
+ {
+ "prefix": "::/0",
+ "protocol": "static",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 1,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 73,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "ip": "2001:1::1",
+ "afi": "ipv6",
+ "interfaceName": "eth0",
+ "active": true,
+ "weight": 1
+ }
+ ]
+ }
+ ],
+ "2001:1::/64": [
+ {
+ "prefix": "2001:1::/64",
+ "protocol": "connected",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth0",
+ "active": true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce1/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce1/zebra.conf
new file mode 100644
index 000000000..58e851d75
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce1/zebra.conf
@@ -0,0 +1,16 @@
+log file zebra.log
+!
+hostname ce1
+!
+interface eth0
+ ip address 192.168.1.2/24
+ ipv6 address 2001:1::2/64
+!
+ip forwarding
+ipv6 forwarding
+!
+ip route 0.0.0.0/0 192.168.1.1
+ipv6 route ::/0 2001:1::1
+!
+line vty
+!
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce2/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce2/bgpd.conf
new file mode 100644
index 000000000..8ed997874
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce2/bgpd.conf
@@ -0,0 +1,8 @@
+frr defaults traditional
+!
+hostname ce2
+password zebra
+!
+log stdout notifications
+log commands
+log file bgpd.log
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce2/ip_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce2/ip_rib.json
new file mode 100644
index 000000000..a21f4a11b
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce2/ip_rib.json
@@ -0,0 +1,58 @@
+{
+ "0.0.0.0/0": [
+ {
+ "prefix": "0.0.0.0/0",
+ "protocol": "static",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 1,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 73,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "ip": "192.168.2.1",
+ "afi": "ipv4",
+ "interfaceName": "eth0",
+ "active": true,
+ "weight": 1
+ }
+ ]
+ }
+ ],
+ "192.168.2.0/24": [
+ {
+ "prefix": "192.168.2.0/24",
+ "protocol": "connected",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth0",
+ "active": true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce2/ipv6_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce2/ipv6_rib.json
new file mode 100644
index 000000000..35ff14efa
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce2/ipv6_rib.json
@@ -0,0 +1,58 @@
+{
+ "::/0": [
+ {
+ "prefix": "::/0",
+ "protocol": "static",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 1,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 73,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "ip": "2001:2::1",
+ "afi": "ipv6",
+ "interfaceName": "eth0",
+ "active": true,
+ "weight": 1
+ }
+ ]
+ }
+ ],
+ "2001:2::/64": [
+ {
+ "prefix": "2001:2::/64",
+ "protocol": "connected",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth0",
+ "active": true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce2/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce2/zebra.conf
new file mode 100644
index 000000000..0612c5322
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce2/zebra.conf
@@ -0,0 +1,16 @@
+log file zebra.log
+!
+hostname ce2
+!
+interface eth0
+ ip address 192.168.2.2/24
+ ipv6 address 2001:2::2/64
+!
+ip forwarding
+ipv6 forwarding
+!
+ip route 0.0.0.0/0 192.168.2.1
+ipv6 route ::/0 2001:2::1
+!
+line vty
+!
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce3/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce3/bgpd.conf
new file mode 100644
index 000000000..a85d9701c
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce3/bgpd.conf
@@ -0,0 +1,8 @@
+frr defaults traditional
+!
+hostname ce3
+password zebra
+!
+log stdout notifications
+log commands
+log file bgpd.log
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce3/ip_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce3/ip_rib.json
new file mode 100644
index 000000000..38a7807df
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce3/ip_rib.json
@@ -0,0 +1,58 @@
+{
+ "0.0.0.0/0": [
+ {
+ "prefix": "0.0.0.0/0",
+ "protocol": "static",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 1,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 73,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "ip": "192.168.3.1",
+ "afi": "ipv4",
+ "interfaceName": "eth0",
+ "active": true,
+ "weight": 1
+ }
+ ]
+ }
+ ],
+ "192.168.3.0/24": [
+ {
+ "prefix": "192.168.3.0/24",
+ "protocol": "connected",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth0",
+ "active": true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce3/ipv6_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce3/ipv6_rib.json
new file mode 100644
index 000000000..2f2931f80
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce3/ipv6_rib.json
@@ -0,0 +1,58 @@
+{
+ "::/0": [
+ {
+ "prefix": "::/0",
+ "protocol": "static",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 1,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 73,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "ip": "2001:3::1",
+ "afi": "ipv6",
+ "interfaceName": "eth0",
+ "active": true,
+ "weight": 1
+ }
+ ]
+ }
+ ],
+ "2001:3::/64": [
+ {
+ "prefix": "2001:3::/64",
+ "protocol": "connected",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth0",
+ "active": true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce3/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce3/zebra.conf
new file mode 100644
index 000000000..d08fdadc3
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce3/zebra.conf
@@ -0,0 +1,16 @@
+log file zebra.log
+!
+hostname ce3
+!
+interface eth0
+ ip address 192.168.3.2/24
+ ipv6 address 2001:3::2/64
+!
+ip forwarding
+ipv6 forwarding
+!
+ip route 0.0.0.0/0 192.168.3.1
+ipv6 route ::/0 2001:3::1
+!
+line vty
+!
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce4/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce4/bgpd.conf
new file mode 100644
index 000000000..93fb32fd1
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce4/bgpd.conf
@@ -0,0 +1,8 @@
+frr defaults traditional
+!
+hostname ce4
+password zebra
+!
+log stdout notifications
+log commands
+log file bgpd.log
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce4/ip_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce4/ip_rib.json
new file mode 100644
index 000000000..a0be78e98
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce4/ip_rib.json
@@ -0,0 +1,58 @@
+{
+ "0.0.0.0/0": [
+ {
+ "prefix": "0.0.0.0/0",
+ "protocol": "static",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 1,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 73,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "ip": "192.168.4.1",
+ "afi": "ipv4",
+ "interfaceName": "eth0",
+ "active": true,
+ "weight": 1
+ }
+ ]
+ }
+ ],
+ "192.168.4.0/24": [
+ {
+ "prefix": "192.168.4.0/24",
+ "protocol": "connected",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth0",
+ "active": true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce4/ipv6_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce4/ipv6_rib.json
new file mode 100644
index 000000000..8a98768e0
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce4/ipv6_rib.json
@@ -0,0 +1,58 @@
+{
+ "::/0": [
+ {
+ "prefix": "::/0",
+ "protocol": "static",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 1,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 73,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "ip": "2001:4::1",
+ "afi": "ipv6",
+ "interfaceName": "eth0",
+ "active": true,
+ "weight": 1
+ }
+ ]
+ }
+ ],
+ "2001:4::/64": [
+ {
+ "prefix": "2001:4::/64",
+ "protocol": "connected",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth0",
+ "active": true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce4/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce4/zebra.conf
new file mode 100644
index 000000000..897ed46c2
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce4/zebra.conf
@@ -0,0 +1,16 @@
+log file zebra.log
+!
+hostname ce4
+!
+interface eth0
+ ip address 192.168.4.2/24
+ ipv6 address 2001:4::2/64
+!
+ip forwarding
+ipv6 forwarding
+!
+ip route 0.0.0.0/0 192.168.4.1
+ipv6 route ::/0 2001:4::1
+!
+line vty
+!
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce5/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce5/bgpd.conf
new file mode 100644
index 000000000..2ab6f2d2a
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce5/bgpd.conf
@@ -0,0 +1,8 @@
+frr defaults traditional
+!
+hostname ce5
+password zebra
+!
+log stdout notifications
+log commands
+log file bgpd.log
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce5/ip_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce5/ip_rib.json
new file mode 100644
index 000000000..dc338d5de
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce5/ip_rib.json
@@ -0,0 +1,58 @@
+{
+ "0.0.0.0/0": [
+ {
+ "prefix": "0.0.0.0/0",
+ "protocol": "static",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 1,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 73,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "ip": "192.168.5.1",
+ "afi": "ipv4",
+ "interfaceName": "eth0",
+ "active": true,
+ "weight": 1
+ }
+ ]
+ }
+ ],
+ "192.168.5.0/24": [
+ {
+ "prefix": "192.168.5.0/24",
+ "protocol": "connected",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth0",
+ "active": true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce5/ipv6_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce5/ipv6_rib.json
new file mode 100644
index 000000000..80ff52ad6
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce5/ipv6_rib.json
@@ -0,0 +1,58 @@
+{
+ "::/0": [
+ {
+ "prefix": "::/0",
+ "protocol": "static",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 1,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 73,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "ip": "2001:5::1",
+ "afi": "ipv6",
+ "interfaceName": "eth0",
+ "active": true,
+ "weight": 1
+ }
+ ]
+ }
+ ],
+ "2001:5::/64": [
+ {
+ "prefix": "2001:5::/64",
+ "protocol": "connected",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth0",
+ "active": true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce5/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce5/zebra.conf
new file mode 100644
index 000000000..a290213f1
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce5/zebra.conf
@@ -0,0 +1,16 @@
+log file zebra.log
+!
+hostname ce5
+!
+interface eth0
+ ip address 192.168.5.2/24
+ ipv6 address 2001:5::2/64
+!
+ip forwarding
+ipv6 forwarding
+!
+ip route 0.0.0.0/0 192.168.5.1
+ipv6 route ::/0 2001:5::1
+!
+line vty
+!
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce6/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce6/bgpd.conf
new file mode 100644
index 000000000..e0b654051
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce6/bgpd.conf
@@ -0,0 +1,8 @@
+frr defaults traditional
+!
+hostname ce6
+password zebra
+!
+log stdout notifications
+log commands
+log file bgpd.log
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce6/ip_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce6/ip_rib.json
new file mode 100644
index 000000000..4a603a55c
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce6/ip_rib.json
@@ -0,0 +1,58 @@
+{
+ "0.0.0.0/0": [
+ {
+ "prefix": "0.0.0.0/0",
+ "protocol": "static",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 1,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 73,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "ip": "192.168.6.1",
+ "afi": "ipv4",
+ "interfaceName": "eth0",
+ "active": true,
+ "weight": 1
+ }
+ ]
+ }
+ ],
+ "192.168.6.0/24": [
+ {
+ "prefix": "192.168.6.0/24",
+ "protocol": "connected",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth0",
+ "active": true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce6/ipv6_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce6/ipv6_rib.json
new file mode 100644
index 000000000..ace6136f0
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce6/ipv6_rib.json
@@ -0,0 +1,58 @@
+{
+ "::/0": [
+ {
+ "prefix": "::/0",
+ "protocol": "static",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 1,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 73,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "ip": "2001:6::1",
+ "afi": "ipv6",
+ "interfaceName": "eth0",
+ "active": true,
+ "weight": 1
+ }
+ ]
+ }
+ ],
+ "2001:6::/64": [
+ {
+ "prefix": "2001:6::/64",
+ "protocol": "connected",
+ "vrfId": 0,
+ "vrfName": "default",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 254,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth0",
+ "active": true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce6/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce6/zebra.conf
new file mode 100644
index 000000000..5a83e901e
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce6/zebra.conf
@@ -0,0 +1,16 @@
+log file zebra.log
+!
+hostname ce6
+!
+interface eth0
+ ip address 192.168.6.2/24
+ ipv6 address 2001:6::2/64
+!
+ip forwarding
+ipv6 forwarding
+!
+ip route 0.0.0.0/0 192.168.6.1
+ipv6 route ::/0 2001:6::1
+!
+line vty
+!
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/bgpd.conf
new file mode 100644
index 000000000..01b0cc3c9
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/bgpd.conf
@@ -0,0 +1,87 @@
+frr defaults traditional
+!
+bgp send-extra-data zebra
+!
+hostname r1
+password zebra
+!
+log stdout notifications
+log monitor notifications
+log commands
+!
+!debug bgp neighbor-events
+!debug bgp zebra
+!debug bgp vnc verbose
+!debug bgp update-groups
+!debug bgp updates in
+!debug bgp updates out
+!debug bgp vpn label
+!debug bgp vpn leak-from-vrf
+!debug bgp vpn leak-to-vrf
+!debug bgp vpn rmap-event
+!
+router bgp 1
+ bgp router-id 1.1.1.1
+ no bgp ebgp-requires-policy
+ !no bgp default ipv4-unicast
+ neighbor 2001::2 remote-as 2
+ neighbor 2001::2 timers 3 10
+ neighbor 2001::2 timers connect 1
+ neighbor 2001::2 capability extended-nexthop
+ !
+ address-family ipv4 vpn
+ neighbor 2001::2 activate
+ exit-address-family
+ !
+ address-family ipv6 vpn
+ neighbor 2001::2 activate
+ exit-address-family
+ !
+ segment-routing srv6
+ locator loc1
+ !
+!
+router bgp 1 vrf vrf10
+ bgp router-id 1.1.1.1
+ no bgp ebgp-requires-policy
+ sid vpn per-vrf export auto
+ !
+ address-family ipv4 unicast
+ nexthop vpn export 2001::1
+ rd vpn export 1:10
+ rt vpn both 99:99
+ import vpn
+ export vpn
+ redistribute connected
+ exit-address-family
+ !
+ address-family ipv6 unicast
+ rd vpn export 1:10
+ rt vpn both 99:99
+ import vpn
+ export vpn
+ redistribute connected
+ exit-address-family
+!
+router bgp 1 vrf vrf20
+ bgp router-id 1.1.1.1
+ no bgp ebgp-requires-policy
+ sid vpn per-vrf export auto
+ !
+ address-family ipv4 unicast
+ nexthop vpn export 2001::1
+ rd vpn export 1:20
+ rt vpn both 88:88
+ import vpn
+ export vpn
+ redistribute connected
+ exit-address-family
+ !
+ address-family ipv6 unicast
+ rd vpn export 1:20
+ rt vpn both 88:88
+ import vpn
+ export vpn
+ redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv4_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv4_rib.json
new file mode 100644
index 000000000..3cc2fddcf
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv4_rib.json
@@ -0,0 +1,167 @@
+{
+ "vrfId": 0,
+ "vrfName": "default",
+ "tableVersion": 2,
+ "routerId": "1.1.1.1",
+ "defaultLocPrf": 100,
+ "localAS": 1,
+ "routes": {
+ "routeDistinguishers": {
+ "1:10": {
+ "192.168.1.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.1.0",
+ "prefixLen": 24,
+ "network": "192.168.1.0/24",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "nhVrfName": "vrf10",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "192.168.3.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.3.0",
+ "prefixLen": 24,
+ "network": "192.168.3.0/24",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "nhVrfName": "vrf10",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "1:20": {
+ "192.168.5.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.5.0",
+ "prefixLen": 24,
+ "network": "192.168.5.0/24",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "nhVrfName": "vrf20",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:10": {
+ "192.168.2.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.2.0",
+ "prefixLen": 24,
+ "network": "192.168.2.0/24",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::2",
+ "path": "2",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:20": {
+ "192.168.4.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.4.0",
+ "prefixLen": 24,
+ "network": "192.168.4.0/24",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::2",
+ "path": "2",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "192.168.6.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.6.0",
+ "prefixLen": 24,
+ "network": "192.168.6.0/24",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::2",
+ "path": "2",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv4_rib_locator_deleted.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv4_rib_locator_deleted.json
new file mode 100644
index 000000000..5645540fb
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv4_rib_locator_deleted.json
@@ -0,0 +1,90 @@
+{
+ "vrfId": 0,
+ "vrfName": "default",
+ "routerId": "1.1.1.1",
+ "defaultLocPrf": 100,
+ "localAS": 1,
+ "routes": {
+ "routeDistinguishers": {
+ "1:10": {
+ "192.168.1.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.1.0",
+ "prefixLen": 24,
+ "network": "192.168.1.0/24",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "nhVrfName": "vrf10",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "192.168.3.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.3.0",
+ "prefixLen": 24,
+ "network": "192.168.3.0/24",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "nhVrfName": "vrf10",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "1:20": {
+ "192.168.5.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.5.0",
+ "prefixLen": 24,
+ "network": "192.168.5.0/24",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "nhVrfName": "vrf20",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv4_rib_locator_recreated.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv4_rib_locator_recreated.json
new file mode 100644
index 000000000..7a4e0d745
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv4_rib_locator_recreated.json
@@ -0,0 +1,166 @@
+{
+ "vrfId": 0,
+ "vrfName": "default",
+ "routerId": "1.1.1.1",
+ "defaultLocPrf": 100,
+ "localAS": 1,
+ "routes": {
+ "routeDistinguishers": {
+ "1:10": {
+ "192.168.1.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.1.0",
+ "prefixLen": 24,
+ "network": "192.168.1.0/24",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "nhVrfName": "vrf10",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "192.168.3.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.3.0",
+ "prefixLen": 24,
+ "network": "192.168.3.0/24",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "nhVrfName": "vrf10",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "1:20": {
+ "192.168.5.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.5.0",
+ "prefixLen": 24,
+ "network": "192.168.5.0/24",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "nhVrfName": "vrf20",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:10": {
+ "192.168.2.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.2.0",
+ "prefixLen": 24,
+ "network": "192.168.2.0/24",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::2",
+ "path": "2",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:20": {
+ "192.168.4.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.4.0",
+ "prefixLen": 24,
+ "network": "192.168.4.0/24",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::2",
+ "path": "2",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "192.168.6.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.6.0",
+ "prefixLen": 24,
+ "network": "192.168.6.0/24",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::2",
+ "path": "2",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv4_rib_sid_vpn_export_disabled.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv4_rib_sid_vpn_export_disabled.json
new file mode 100644
index 000000000..eb3433301
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv4_rib_sid_vpn_export_disabled.json
@@ -0,0 +1,115 @@
+{
+ "vrfId": 0,
+ "vrfName": "default",
+ "tableVersion": 4,
+ "routerId": "1.1.1.1",
+ "defaultLocPrf": 100,
+ "localAS": 1,
+ "routes": {
+ "routeDistinguishers": {
+ "1:20": {
+ "192.168.5.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.5.0",
+ "prefixLen": 24,
+ "network": "192.168.5.0/24",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "nhVrfName": "vrf20",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:10": {
+ "192.168.2.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.2.0",
+ "prefixLen": 24,
+ "network": "192.168.2.0/24",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::2",
+ "path": "2",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:20": {
+ "192.168.4.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.4.0",
+ "prefixLen": 24,
+ "network": "192.168.4.0/24",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::2",
+ "path": "2",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "192.168.6.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.6.0",
+ "prefixLen": 24,
+ "network": "192.168.6.0/24",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::2",
+ "path": "2",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv4_rib_sid_vpn_export_reenabled.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv4_rib_sid_vpn_export_reenabled.json
new file mode 100644
index 000000000..5517fc738
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv4_rib_sid_vpn_export_reenabled.json
@@ -0,0 +1,167 @@
+{
+ "vrfId": 0,
+ "vrfName": "default",
+ "tableVersion": 6,
+ "routerId": "1.1.1.1",
+ "defaultLocPrf": 100,
+ "localAS": 1,
+ "routes": {
+ "routeDistinguishers": {
+ "1:10": {
+ "192.168.1.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.1.0",
+ "prefixLen": 24,
+ "network": "192.168.1.0/24",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "nhVrfName": "vrf10",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "192.168.3.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.3.0",
+ "prefixLen": 24,
+ "network": "192.168.3.0/24",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "nhVrfName": "vrf10",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "1:20": {
+ "192.168.5.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.5.0",
+ "prefixLen": 24,
+ "network": "192.168.5.0/24",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "nhVrfName": "vrf20",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:10": {
+ "192.168.2.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.2.0",
+ "prefixLen": 24,
+ "network": "192.168.2.0/24",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::2",
+ "path": "2",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:20": {
+ "192.168.4.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.4.0",
+ "prefixLen": 24,
+ "network": "192.168.4.0/24",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::2",
+ "path": "2",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "192.168.6.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.6.0",
+ "prefixLen": 24,
+ "network": "192.168.6.0/24",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::2",
+ "path": "2",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv6_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv6_rib.json
new file mode 100644
index 000000000..25b7a8616
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv6_rib.json
@@ -0,0 +1,170 @@
+{
+ "vrfId": 0,
+ "vrfName": "default",
+ "tableVersion": 2,
+ "routerId": "1.1.1.1",
+ "defaultLocPrf": 100,
+ "localAS": 1,
+ "routes": {
+ "routeDistinguishers": {
+ "1:10": {
+ "2001:1::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:1::",
+ "prefixLen": 64,
+ "network": "2001:1::/64",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf10",
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:3::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:3::",
+ "prefixLen": 64,
+ "network": "2001:3::/64",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf10",
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "1:20": {
+ "2001:5::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:5::",
+ "prefixLen": 64,
+ "network": "2001:5::/64",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf20",
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:10": {
+ "2001:2::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:2::",
+ "prefixLen": 64,
+ "network": "2001:2::/64",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::2",
+ "path": "2",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:20": {
+ "2001:4::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:4::",
+ "prefixLen": 64,
+ "network": "2001:4::/64",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::2",
+ "path": "2",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:6::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:6::",
+ "prefixLen": 64,
+ "network": "2001:6::/64",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::2",
+ "path": "2",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv6_rib_locator_deleted.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv6_rib_locator_deleted.json
new file mode 100644
index 000000000..f2df9be49
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv6_rib_locator_deleted.json
@@ -0,0 +1,160 @@
+{
+ "vrfId": 0,
+ "vrfName": "default",
+ "routerId": "1.1.1.1",
+ "defaultLocPrf": 100,
+ "localAS": 1,
+ "routes": {
+ "routeDistinguishers": {
+ "1:10": {
+ "2001:1::/64": [
+ {
+ "pathFrom": "external",
+ "prefix": "2001:1::",
+ "prefixLen": 64,
+ "network": "2001:1::/64",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf10",
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:3::/64": [
+ {
+ "pathFrom": "external",
+ "prefix": "2001:3::",
+ "prefixLen": 64,
+ "network": "2001:3::/64",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf10",
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "1:20": {
+ "2001:5::/64": [
+ {
+ "pathFrom": "external",
+ "prefix": "2001:5::",
+ "prefixLen": 64,
+ "network": "2001:5::/64",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf20",
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:10": {
+ "2001:2::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:2::",
+ "prefixLen": 64,
+ "network": "2001:2::/64",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::2",
+ "path": "2",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:20": {
+ "2001:4::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:4::",
+ "prefixLen": 64,
+ "network": "2001:4::/64",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::2",
+ "path": "2",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:6::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:6::",
+ "prefixLen": 64,
+ "network": "2001:6::/64",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::2",
+ "path": "2",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv6_rib_locator_recreated.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv6_rib_locator_recreated.json
new file mode 100644
index 000000000..0fdd3d6dc
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv6_rib_locator_recreated.json
@@ -0,0 +1,169 @@
+{
+ "vrfId": 0,
+ "vrfName": "default",
+ "routerId": "1.1.1.1",
+ "defaultLocPrf": 100,
+ "localAS": 1,
+ "routes": {
+ "routeDistinguishers": {
+ "1:10": {
+ "2001:1::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:1::",
+ "prefixLen": 64,
+ "network": "2001:1::/64",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf10",
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:3::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:3::",
+ "prefixLen": 64,
+ "network": "2001:3::/64",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf10",
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "1:20": {
+ "2001:5::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:5::",
+ "prefixLen": 64,
+ "network": "2001:5::/64",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf20",
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:10": {
+ "2001:2::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:2::",
+ "prefixLen": 64,
+ "network": "2001:2::/64",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::2",
+ "path": "2",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:20": {
+ "2001:4::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:4::",
+ "prefixLen": 64,
+ "network": "2001:4::/64",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::2",
+ "path": "2",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:6::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:6::",
+ "prefixLen": 64,
+ "network": "2001:6::/64",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::2",
+ "path": "2",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv6_rib_sid_vpn_export_disabled.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv6_rib_sid_vpn_export_disabled.json
new file mode 100644
index 000000000..a1f21585d
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv6_rib_sid_vpn_export_disabled.json
@@ -0,0 +1,116 @@
+{
+ "vrfId": 0,
+ "vrfName": "default",
+ "tableVersion": 4,
+ "routerId": "1.1.1.1",
+ "defaultLocPrf": 100,
+ "localAS": 1,
+ "routes": {
+ "routeDistinguishers": {
+ "1:20": {
+ "2001:5::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:5::",
+ "prefixLen": 64,
+ "network": "2001:5::/64",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf20",
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:10": {
+ "2001:2::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:2::",
+ "prefixLen": 64,
+ "network": "2001:2::/64",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::2",
+ "path": "2",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:20": {
+ "2001:4::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:4::",
+ "prefixLen": 64,
+ "network": "2001:4::/64",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::2",
+ "path": "2",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:6::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:6::",
+ "prefixLen": 64,
+ "network": "2001:6::/64",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::2",
+ "path": "2",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv6_rib_sid_vpn_export_reenabled.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv6_rib_sid_vpn_export_reenabled.json
new file mode 100644
index 000000000..7eeccd149
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv6_rib_sid_vpn_export_reenabled.json
@@ -0,0 +1,170 @@
+{
+ "vrfId": 0,
+ "vrfName": "default",
+ "tableVersion": 6,
+ "routerId": "1.1.1.1",
+ "defaultLocPrf": 100,
+ "localAS": 1,
+ "routes": {
+ "routeDistinguishers": {
+ "1:10": {
+ "2001:1::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:1::",
+ "prefixLen": 64,
+ "network": "2001:1::/64",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf10",
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:3::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:3::",
+ "prefixLen": 64,
+ "network": "2001:3::/64",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf10",
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "1:20": {
+ "2001:5::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:5::",
+ "prefixLen": 64,
+ "network": "2001:5::/64",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf20",
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:10": {
+ "2001:2::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:2::",
+ "prefixLen": 64,
+ "network": "2001:2::/64",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::2",
+ "path": "2",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:20": {
+ "2001:4::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:4::",
+ "prefixLen": 64,
+ "network": "2001:4::/64",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::2",
+ "path": "2",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:6::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:6::",
+ "prefixLen": 64,
+ "network": "2001:6::/64",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::2",
+ "path": "2",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vrf10v4_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vrf10v4_rib.json
new file mode 100644
index 000000000..cc96f4318
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vrf10v4_rib.json
@@ -0,0 +1,86 @@
+{
+ "192.168.1.0/24": [
+ {
+ "prefix": "192.168.1.0/24",
+ "protocol": "connected",
+ "vrfName": "vrf10",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 10,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth1",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "192.168.2.0/24": [
+ {
+ "prefix": "192.168.2.0/24",
+ "protocol": "bgp",
+ "vrfName": "vrf10",
+ "selected": true,
+ "destSelected": true,
+ "distance": 20,
+ "metric": 0,
+ "installed": true,
+ "table": 10,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "afi": "ipv6",
+ "interfaceName": "eth0",
+ "vrf": "default",
+ "active": true,
+ "weight": 1,
+ "seg6": {
+ "segs": "2001:db8:2:2:1::"
+ }
+ }
+ ],
+ "asPath": "2"
+ }
+ ],
+ "192.168.3.0/24": [
+ {
+ "prefix": "192.168.3.0/24",
+ "protocol": "connected",
+ "vrfName": "vrf10",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 10,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth2",
+ "active": true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vrf10v6_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vrf10v6_rib.json
new file mode 100644
index 000000000..0c9ae73ef
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vrf10v6_rib.json
@@ -0,0 +1,86 @@
+{
+ "2001:1::/64": [
+ {
+ "prefix": "2001:1::/64",
+ "protocol": "connected",
+ "vrfName": "vrf10",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 10,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth1",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "2001:2::/64": [
+ {
+ "prefix": "2001:2::/64",
+ "protocol": "bgp",
+ "vrfName": "vrf10",
+ "selected": true,
+ "destSelected": true,
+ "distance": 20,
+ "metric": 0,
+ "installed": true,
+ "table": 10,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "afi": "ipv6",
+ "interfaceName": "eth0",
+ "vrf": "default",
+ "active": true,
+ "weight": 1,
+ "seg6": {
+ "segs": "2001:db8:2:2:1::"
+ }
+ }
+ ],
+ "asPath": "2"
+ }
+ ],
+ "2001:3::/64": [
+ {
+ "prefix": "2001:3::/64",
+ "protocol": "connected",
+ "vrfName": "vrf10",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 10,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth2",
+ "active": true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vrf20v4_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vrf20v4_rib.json
new file mode 100644
index 000000000..cf0fd188e
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vrf20v4_rib.json
@@ -0,0 +1,92 @@
+{
+ "192.168.4.0/24": [
+ {
+ "prefix": "192.168.4.0/24",
+ "protocol": "bgp",
+ "vrfName": "vrf20",
+ "selected": true,
+ "destSelected": true,
+ "distance": 20,
+ "metric": 0,
+ "installed": true,
+ "table": 20,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "afi": "ipv6",
+ "interfaceName": "eth0",
+ "vrf": "default",
+ "active": true,
+ "weight": 1,
+ "seg6": {
+ "segs": "2001:db8:2:2:2::"
+ }
+ }
+ ],
+ "asPath": "2"
+ }
+ ],
+ "192.168.5.0/24": [
+ {
+ "prefix": "192.168.5.0/24",
+ "protocol": "connected",
+ "vrfName": "vrf20",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 20,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth3",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "192.168.6.0/24": [
+ {
+ "prefix": "192.168.6.0/24",
+ "protocol": "bgp",
+ "vrfName": "vrf20",
+ "selected": true,
+ "destSelected": true,
+ "distance": 20,
+ "metric": 0,
+ "installed": true,
+ "table": 20,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "afi": "ipv6",
+ "interfaceName": "eth0",
+ "vrf": "default",
+ "active": true,
+ "weight": 1,
+ "seg6": {
+ "segs": "2001:db8:2:2:2::"
+ }
+ }
+ ],
+ "asPath": "2"
+ }
+ ]
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vrf20v6_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vrf20v6_rib.json
new file mode 100644
index 000000000..e486e7454
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vrf20v6_rib.json
@@ -0,0 +1,92 @@
+{
+ "2001:4::/64": [
+ {
+ "prefix": "2001:4::/64",
+ "protocol": "bgp",
+ "vrfName": "vrf20",
+ "selected": true,
+ "destSelected": true,
+ "distance": 20,
+ "metric": 0,
+ "installed": true,
+ "table": 20,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "afi": "ipv6",
+ "interfaceName": "eth0",
+ "vrf": "default",
+ "active": true,
+ "weight": 1,
+ "seg6": {
+ "segs": "2001:db8:2:2:2::"
+ }
+ }
+ ],
+ "asPath": "2"
+ }
+ ],
+ "2001:5::/64": [
+ {
+ "prefix": "2001:5::/64",
+ "protocol": "connected",
+ "vrfName": "vrf20",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 20,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth3",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "2001:6::/64": [
+ {
+ "prefix": "2001:6::/64",
+ "protocol": "bgp",
+ "vrfName": "vrf20",
+ "selected": true,
+ "destSelected": true,
+ "distance": 20,
+ "metric": 0,
+ "installed": true,
+ "table": 20,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "afi": "ipv6",
+ "interfaceName": "eth0",
+ "vrf": "default",
+ "active": true,
+ "weight": 1,
+ "seg6": {
+ "segs": "2001:db8:2:2:2::"
+ }
+ }
+ ],
+ "asPath": "2"
+ }
+ ]
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/zebra.conf
new file mode 100644
index 000000000..2c560dfc0
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/zebra.conf
@@ -0,0 +1,43 @@
+log file zebra.log
+!
+hostname r1
+password zebra
+!
+log stdout notifications
+log monitor notifications
+log commands
+!
+debug zebra packet
+debug zebra dplane
+debug zebra kernel
+!
+interface eth0
+ ipv6 address 2001::1/64
+!
+interface eth1 vrf vrf10
+ ip address 192.168.1.1/24
+ ipv6 address 2001:1::1/64
+!
+interface eth2 vrf vrf10
+ ip address 192.168.3.1/24
+ ipv6 address 2001:3::1/64
+!
+interface eth3 vrf vrf20
+ ip address 192.168.5.1/24
+ ipv6 address 2001:5::1/64
+!
+segment-routing
+ srv6
+ locators
+ locator loc1
+ prefix 2001:db8:1:1::/64
+ !
+ !
+!
+ip forwarding
+ipv6 forwarding
+!
+ipv6 route 2001:db8:2:2::/64 2001::2
+!
+line vty
+!
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/bgpd.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/bgpd.conf
new file mode 100644
index 000000000..8700f12d6
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/bgpd.conf
@@ -0,0 +1,88 @@
+frr defaults traditional
+!
+bgp send-extra-data zebra
+!
+hostname r2
+password zebra
+!
+log stdout notifications
+log monitor notifications
+log commands
+!
+!debug bgp neighbor-events
+!debug bgp zebra
+!debug bgp vnc verbose
+!debug bgp update-groups
+!debug bgp updates in
+!debug bgp updates out
+!debug bgp updates
+!debug bgp vpn label
+!debug bgp vpn leak-from-vrf
+!debug bgp vpn leak-to-vrf
+!debug bgp vpn rmap-event
+!
+router bgp 2
+ bgp router-id 2.2.2.2
+ no bgp ebgp-requires-policy
+ !no bgp default ipv4-unicast
+ neighbor 2001::1 remote-as 1
+ neighbor 2001::1 timers 3 10
+ neighbor 2001::1 timers connect 1
+ neighbor 2001::1 capability extended-nexthop
+ !
+ address-family ipv4 vpn
+ neighbor 2001::1 activate
+ exit-address-family
+ !
+ address-family ipv6 vpn
+ neighbor 2001::1 activate
+ exit-address-family
+ !
+ segment-routing srv6
+ locator loc1
+ !
+!
+router bgp 2 vrf vrf10
+ bgp router-id 2.2.2.2
+ no bgp ebgp-requires-policy
+ sid vpn per-vrf export auto
+ !
+ address-family ipv4 unicast
+ nexthop vpn export 2001::2
+ rd vpn export 2:10
+ rt vpn both 99:99
+ import vpn
+ export vpn
+ redistribute connected
+ exit-address-family
+ !
+ address-family ipv6 unicast
+ rd vpn export 2:10
+ rt vpn both 99:99
+ import vpn
+ export vpn
+ redistribute connected
+ exit-address-family
+!
+router bgp 2 vrf vrf20
+ bgp router-id 2.2.2.2
+ no bgp ebgp-requires-policy
+ sid vpn per-vrf export auto
+ !
+ address-family ipv4 unicast
+ nexthop vpn export 2001::2
+ rd vpn export 2:20
+ rt vpn both 88:88
+ import vpn
+ export vpn
+ redistribute connected
+ exit-address-family
+ !
+ address-family ipv6 unicast
+ rd vpn export 2:20
+ rt vpn both 88:88
+ import vpn
+ export vpn
+ redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv4_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv4_rib.json
new file mode 100644
index 000000000..95570541c
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv4_rib.json
@@ -0,0 +1,167 @@
+{
+ "vrfId": 0,
+ "vrfName": "default",
+ "tableVersion": 2,
+ "routerId": "2.2.2.2",
+ "defaultLocPrf": 100,
+ "localAS": 2,
+ "routes": {
+ "routeDistinguishers": {
+ "1:10": {
+ "192.168.1.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.1.0",
+ "prefixLen": 24,
+ "network": "192.168.1.0/24",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::1",
+ "path": "1",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "192.168.3.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.3.0",
+ "prefixLen": 24,
+ "network": "192.168.3.0/24",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::1",
+ "path": "1",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "1:20": {
+ "192.168.5.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.5.0",
+ "prefixLen": 24,
+ "network": "192.168.5.0/24",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::1",
+ "path": "1",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:10": {
+ "192.168.2.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.2.0",
+ "prefixLen": 24,
+ "network": "192.168.2.0/24",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "nhVrfName": "vrf10",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:20": {
+ "192.168.4.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.4.0",
+ "prefixLen": 24,
+ "network": "192.168.4.0/24",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "nhVrfName": "vrf20",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "192.168.6.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.6.0",
+ "prefixLen": 24,
+ "network": "192.168.6.0/24",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "nhVrfName": "vrf20",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv4_rib_locator_deleted.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv4_rib_locator_deleted.json
new file mode 100644
index 000000000..e3edee172
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv4_rib_locator_deleted.json
@@ -0,0 +1,90 @@
+{
+ "vrfId": 0,
+ "vrfName": "default",
+ "routerId": "2.2.2.2",
+ "defaultLocPrf": 100,
+ "localAS": 2,
+ "routes": {
+ "routeDistinguishers": {
+ "2:10": {
+ "192.168.2.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.2.0",
+ "prefixLen": 24,
+ "network": "192.168.2.0/24",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "nhVrfName": "vrf10",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:20": {
+ "192.168.4.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.4.0",
+ "prefixLen": 24,
+ "network": "192.168.4.0/24",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "nhVrfName": "vrf20",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "192.168.6.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.6.0",
+ "prefixLen": 24,
+ "network": "192.168.6.0/24",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "nhVrfName": "vrf20",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv4_rib_locator_recreated.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv4_rib_locator_recreated.json
new file mode 100644
index 000000000..0dcdec678
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv4_rib_locator_recreated.json
@@ -0,0 +1,166 @@
+{
+ "vrfId": 0,
+ "vrfName": "default",
+ "routerId": "2.2.2.2",
+ "defaultLocPrf": 100,
+ "localAS": 2,
+ "routes": {
+ "routeDistinguishers": {
+ "1:10": {
+ "192.168.1.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.1.0",
+ "prefixLen": 24,
+ "network": "192.168.1.0/24",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::1",
+ "path": "1",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "192.168.3.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.3.0",
+ "prefixLen": 24,
+ "network": "192.168.3.0/24",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::1",
+ "path": "1",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "1:20": {
+ "192.168.5.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.5.0",
+ "prefixLen": 24,
+ "network": "192.168.5.0/24",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::1",
+ "path": "1",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:10": {
+ "192.168.2.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.2.0",
+ "prefixLen": 24,
+ "network": "192.168.2.0/24",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "nhVrfName": "vrf10",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:20": {
+ "192.168.4.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.4.0",
+ "prefixLen": 24,
+ "network": "192.168.4.0/24",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "nhVrfName": "vrf20",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "192.168.6.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.6.0",
+ "prefixLen": 24,
+ "network": "192.168.6.0/24",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "nhVrfName": "vrf20",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv4_rib_sid_vpn_export_disabled.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv4_rib_sid_vpn_export_disabled.json
new file mode 100644
index 000000000..d801671fd
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv4_rib_sid_vpn_export_disabled.json
@@ -0,0 +1,117 @@
+{
+ "vrfId": 0,
+ "vrfName": "default",
+ "tableVersion": 4,
+ "routerId": "2.2.2.2",
+ "defaultLocPrf": 100,
+ "localAS": 2,
+ "routes": {
+ "routeDistinguishers": {
+ "1:20": {
+ "192.168.5.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.5.0",
+ "prefixLen": 24,
+ "network": "192.168.5.0/24",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::1",
+ "path": "1",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:10": {
+ "192.168.2.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.2.0",
+ "prefixLen": 24,
+ "network": "192.168.2.0/24",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "nhVrfName": "vrf10",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:20": {
+ "192.168.4.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.4.0",
+ "prefixLen": 24,
+ "network": "192.168.4.0/24",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "nhVrfName": "vrf20",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "192.168.6.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.6.0",
+ "prefixLen": 24,
+ "network": "192.168.6.0/24",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "nhVrfName": "vrf20",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv4_rib_sid_vpn_export_reenabled.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv4_rib_sid_vpn_export_reenabled.json
new file mode 100644
index 000000000..25da05b0d
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv4_rib_sid_vpn_export_reenabled.json
@@ -0,0 +1,167 @@
+{
+ "vrfId": 0,
+ "vrfName": "default",
+ "tableVersion": 6,
+ "routerId": "2.2.2.2",
+ "defaultLocPrf": 100,
+ "localAS": 2,
+ "routes": {
+ "routeDistinguishers": {
+ "1:10": {
+ "192.168.1.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.1.0",
+ "prefixLen": 24,
+ "network": "192.168.1.0/24",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::1",
+ "path": "1",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "192.168.3.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.3.0",
+ "prefixLen": 24,
+ "network": "192.168.3.0/24",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::1",
+ "path": "1",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "1:20": {
+ "192.168.5.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.5.0",
+ "prefixLen": 24,
+ "network": "192.168.5.0/24",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::1",
+ "path": "1",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:10": {
+ "192.168.2.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.2.0",
+ "prefixLen": 24,
+ "network": "192.168.2.0/24",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "nhVrfName": "vrf10",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:20": {
+ "192.168.4.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.4.0",
+ "prefixLen": 24,
+ "network": "192.168.4.0/24",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "nhVrfName": "vrf20",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "192.168.6.0/24": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "192.168.6.0",
+ "prefixLen": 24,
+ "network": "192.168.6.0/24",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "nhVrfName": "vrf20",
+ "nexthops": [
+ {
+ "ip": "2001::2",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv6_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv6_rib.json
new file mode 100644
index 000000000..2cd47b9ce
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv6_rib.json
@@ -0,0 +1,170 @@
+{
+ "vrfId": 0,
+ "vrfName": "default",
+ "tableVersion": 2,
+ "routerId": "2.2.2.2",
+ "defaultLocPrf": 100,
+ "localAS": 2,
+ "routes": {
+ "routeDistinguishers": {
+ "1:10": {
+ "2001:1::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:1::",
+ "prefixLen": 64,
+ "network": "2001:1::/64",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::1",
+ "path": "1",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:3::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:3::",
+ "prefixLen": 64,
+ "network": "2001:3::/64",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::1",
+ "path": "1",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "1:20": {
+ "2001:5::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:5::",
+ "prefixLen": 64,
+ "network": "2001:5::/64",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::1",
+ "path": "1",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:10": {
+ "2001:2::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:2::",
+ "prefixLen": 64,
+ "network": "2001:2::/64",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf10",
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:20": {
+ "2001:4::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:4::",
+ "prefixLen": 64,
+ "network": "2001:4::/64",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf20",
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:6::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:6::",
+ "prefixLen": 64,
+ "network": "2001:6::/64",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf20",
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv6_rib_locator_deleted.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv6_rib_locator_deleted.json
new file mode 100644
index 000000000..25cdf031c
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv6_rib_locator_deleted.json
@@ -0,0 +1,93 @@
+{
+ "vrfId": 0,
+ "vrfName": "default",
+ "routerId": "2.2.2.2",
+ "defaultLocPrf": 100,
+ "localAS": 2,
+ "routes": {
+ "routeDistinguishers": {
+ "2:10": {
+ "2001:2::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:2::",
+ "prefixLen": 64,
+ "network": "2001:2::/64",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf10",
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:20": {
+ "2001:4::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:4::",
+ "prefixLen": 64,
+ "network": "2001:4::/64",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf20",
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:6::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:6::",
+ "prefixLen": 64,
+ "network": "2001:6::/64",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf20",
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv6_rib_locator_recreated.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv6_rib_locator_recreated.json
new file mode 100644
index 000000000..03bbcc008
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv6_rib_locator_recreated.json
@@ -0,0 +1,169 @@
+{
+ "vrfId": 0,
+ "vrfName": "default",
+ "routerId": "2.2.2.2",
+ "defaultLocPrf": 100,
+ "localAS": 2,
+ "routes": {
+ "routeDistinguishers": {
+ "1:10": {
+ "2001:1::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:1::",
+ "prefixLen": 64,
+ "network": "2001:1::/64",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::1",
+ "path": "1",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:3::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:3::",
+ "prefixLen": 64,
+ "network": "2001:3::/64",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::1",
+ "path": "1",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "1:20": {
+ "2001:5::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:5::",
+ "prefixLen": 64,
+ "network": "2001:5::/64",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::1",
+ "path": "1",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:10": {
+ "2001:2::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:2::",
+ "prefixLen": 64,
+ "network": "2001:2::/64",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf10",
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:20": {
+ "2001:4::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:4::",
+ "prefixLen": 64,
+ "network": "2001:4::/64",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf20",
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:6::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:6::",
+ "prefixLen": 64,
+ "network": "2001:6::/64",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf20",
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv6_rib_sid_vpn_export_disabled.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv6_rib_sid_vpn_export_disabled.json
new file mode 100644
index 000000000..f390ef69b
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv6_rib_sid_vpn_export_disabled.json
@@ -0,0 +1,120 @@
+{
+ "vrfId": 0,
+ "vrfName": "default",
+ "tableVersion": 4,
+ "routerId": "2.2.2.2",
+ "defaultLocPrf": 100,
+ "localAS": 2,
+ "routes": {
+ "routeDistinguishers": {
+ "1:20": {
+ "2001:5::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:5::",
+ "prefixLen": 64,
+ "network": "2001:5::/64",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::1",
+ "path": "1",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:10": {
+ "2001:2::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:2::",
+ "prefixLen": 64,
+ "network": "2001:2::/64",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf10",
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:20": {
+ "2001:4::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:4::",
+ "prefixLen": 64,
+ "network": "2001:4::/64",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf20",
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:6::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:6::",
+ "prefixLen": 64,
+ "network": "2001:6::/64",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf20",
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv6_rib_sid_vpn_export_reenabled.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv6_rib_sid_vpn_export_reenabled.json
new file mode 100644
index 000000000..3353d75ed
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv6_rib_sid_vpn_export_reenabled.json
@@ -0,0 +1,170 @@
+{
+ "vrfId": 0,
+ "vrfName": "default",
+ "tableVersion": 6,
+ "routerId": "2.2.2.2",
+ "defaultLocPrf": 100,
+ "localAS": 2,
+ "routes": {
+ "routeDistinguishers": {
+ "1:10": {
+ "2001:1::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:1::",
+ "prefixLen": 64,
+ "network": "2001:1::/64",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::1",
+ "path": "1",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:3::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:3::",
+ "prefixLen": 64,
+ "network": "2001:3::/64",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::1",
+ "path": "1",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "1:20": {
+ "2001:5::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:5::",
+ "prefixLen": 64,
+ "network": "2001:5::/64",
+ "metric": 0,
+ "weight": 0,
+ "peerId": "2001::1",
+ "path": "1",
+ "origin": "incomplete",
+ "nexthops": [
+ {
+ "ip": "2001::1",
+ "hostname": "r1",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:10": {
+ "2001:2::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:2::",
+ "prefixLen": 64,
+ "network": "2001:2::/64",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf10",
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ },
+ "2:20": {
+ "2001:4::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:4::",
+ "prefixLen": 64,
+ "network": "2001:4::/64",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf20",
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ],
+ "2001:6::/64": [
+ {
+ "valid": true,
+ "bestpath": true,
+ "selectionReason": "First path received",
+ "pathFrom": "external",
+ "prefix": "2001:6::",
+ "prefixLen": 64,
+ "network": "2001:6::/64",
+ "metric": 0,
+ "weight": 32768,
+ "peerId": "(unspec)",
+ "path": "",
+ "origin": "incomplete",
+ "announceNexthopSelf": true,
+ "nhVrfName": "vrf20",
+ "nexthops": [
+ {
+ "ip": "::",
+ "hostname": "r2",
+ "afi": "ipv6",
+ "used": true
+ }
+ ]
+ }
+ ]
+ }
+ }
+ }
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vrf10v4_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vrf10v4_rib.json
new file mode 100644
index 000000000..1534e984b
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vrf10v4_rib.json
@@ -0,0 +1,92 @@
+{
+ "192.168.1.0/24": [
+ {
+ "prefix": "192.168.1.0/24",
+ "protocol": "bgp",
+ "vrfName": "vrf10",
+ "selected": true,
+ "destSelected": true,
+ "distance": 20,
+ "metric": 0,
+ "installed": true,
+ "table": 10,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "afi": "ipv6",
+ "interfaceName": "eth0",
+ "vrf": "default",
+ "active": true,
+ "weight": 1,
+ "seg6": {
+ "segs": "2001:db8:1:1:1::"
+ }
+ }
+ ],
+ "asPath": "1"
+ }
+ ],
+ "192.168.2.0/24": [
+ {
+ "prefix": "192.168.2.0/24",
+ "protocol": "connected",
+ "vrfName": "vrf10",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 10,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth1",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "192.168.3.0/24": [
+ {
+ "prefix": "192.168.3.0/24",
+ "protocol": "bgp",
+ "vrfName": "vrf10",
+ "selected": true,
+ "destSelected": true,
+ "distance": 20,
+ "metric": 0,
+ "installed": true,
+ "table": 10,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "afi": "ipv6",
+ "interfaceName": "eth0",
+ "vrf": "default",
+ "active": true,
+ "weight": 1,
+ "seg6": {
+ "segs": "2001:db8:1:1:1::"
+ }
+ }
+ ],
+ "asPath": "1"
+ }
+ ]
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vrf10v6_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vrf10v6_rib.json
new file mode 100644
index 000000000..a2e329d0d
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vrf10v6_rib.json
@@ -0,0 +1,92 @@
+{
+ "2001:1::/64": [
+ {
+ "prefix": "2001:1::/64",
+ "protocol": "bgp",
+ "vrfName": "vrf10",
+ "selected": true,
+ "destSelected": true,
+ "distance": 20,
+ "metric": 0,
+ "installed": true,
+ "table": 10,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "afi": "ipv6",
+ "interfaceName": "eth0",
+ "vrf": "default",
+ "active": true,
+ "weight": 1,
+ "seg6": {
+ "segs": "2001:db8:1:1:1::"
+ }
+ }
+ ],
+ "asPath": "1"
+ }
+ ],
+ "2001:2::/64": [
+ {
+ "prefix": "2001:2::/64",
+ "protocol": "connected",
+ "vrfName": "vrf10",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 10,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth1",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "2001:3::/64": [
+ {
+ "prefix": "2001:3::/64",
+ "protocol": "bgp",
+ "vrfName": "vrf10",
+ "selected": true,
+ "destSelected": true,
+ "distance": 20,
+ "metric": 0,
+ "installed": true,
+ "table": 10,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "afi": "ipv6",
+ "interfaceName": "eth0",
+ "vrf": "default",
+ "active": true,
+ "weight": 1,
+ "seg6": {
+ "segs": "2001:db8:1:1:1::"
+ }
+ }
+ ],
+ "asPath": "1"
+ }
+ ]
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vrf20v4_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vrf20v4_rib.json
new file mode 100644
index 000000000..49d18614a
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vrf20v4_rib.json
@@ -0,0 +1,86 @@
+{
+ "192.168.4.0/24": [
+ {
+ "prefix": "192.168.4.0/24",
+ "protocol": "connected",
+ "vrfName": "vrf20",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 20,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth2",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "192.168.5.0/24": [
+ {
+ "prefix": "192.168.5.0/24",
+ "protocol": "bgp",
+ "vrfName": "vrf20",
+ "selected": true,
+ "destSelected": true,
+ "distance": 20,
+ "metric": 0,
+ "installed": true,
+ "table": 20,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "afi": "ipv6",
+ "interfaceName": "eth0",
+ "vrf": "default",
+ "active": true,
+ "weight": 1,
+ "seg6": {
+ "segs": "2001:db8:1:1:2::"
+ }
+ }
+ ],
+ "asPath": "1"
+ }
+ ],
+ "192.168.6.0/24": [
+ {
+ "prefix": "192.168.6.0/24",
+ "protocol": "connected",
+ "vrfName": "vrf20",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 20,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth3",
+ "active": true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vrf20v6_rib.json b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vrf20v6_rib.json
new file mode 100644
index 000000000..f7433d5d7
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vrf20v6_rib.json
@@ -0,0 +1,86 @@
+{
+ "2001:4::/64": [
+ {
+ "prefix": "2001:4::/64",
+ "protocol": "connected",
+ "vrfName": "vrf20",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 20,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth2",
+ "active": true
+ }
+ ]
+ }
+ ],
+ "2001:5::/64": [
+ {
+ "prefix": "2001:5::/64",
+ "protocol": "bgp",
+ "vrfName": "vrf20",
+ "selected": true,
+ "destSelected": true,
+ "distance": 20,
+ "metric": 0,
+ "installed": true,
+ "table": 20,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "afi": "ipv6",
+ "interfaceName": "eth0",
+ "vrf": "default",
+ "active": true,
+ "weight": 1,
+ "seg6": {
+ "segs": "2001:db8:1:1:2::"
+ }
+ }
+ ],
+ "asPath": "1"
+ }
+ ],
+ "2001:6::/64": [
+ {
+ "prefix": "2001:6::/64",
+ "protocol": "connected",
+ "vrfName": "vrf20",
+ "selected": true,
+ "destSelected": true,
+ "distance": 0,
+ "metric": 0,
+ "installed": true,
+ "table": 20,
+ "internalStatus": 16,
+ "internalFlags": 8,
+ "internalNextHopNum": 1,
+ "internalNextHopActiveNum": 1,
+ "nexthops": [
+ {
+ "flags": 3,
+ "fib": true,
+ "directlyConnected": true,
+ "interfaceName": "eth3",
+ "active": true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/zebra.conf
new file mode 100644
index 000000000..b9277a9a8
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/zebra.conf
@@ -0,0 +1,43 @@
+log file zebra.log
+!
+hostname r2
+password zebra
+!
+log stdout notifications
+log monitor notifications
+log commands
+!
+debug zebra packet
+debug zebra dplane
+debug zebra kernel
+!
+interface eth0
+ ipv6 address 2001::2/64
+!
+interface eth1 vrf vrf10
+ ip address 192.168.2.1/24
+ ipv6 address 2001:2::1/64
+!
+interface eth2 vrf vrf20
+ ip address 192.168.4.1/24
+ ipv6 address 2001:4::1/64
+!
+interface eth3 vrf vrf20
+ ip address 192.168.6.1/24
+ ipv6 address 2001:6::1/64
+!
+segment-routing
+ srv6
+ locators
+ locator loc1
+ prefix 2001:db8:2:2::/64
+ !
+ !
+!
+ip forwarding
+ipv6 forwarding
+!
+ipv6 route 2001:db8:1:1::/64 2001::1
+!
+line vty
+!
diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py
new file mode 100644
index 000000000..e410bbbde
--- /dev/null
+++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py
@@ -0,0 +1,362 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2022, University of Rome Tor Vergata
+# Authored by Carmine Scarpitta <carmine.scarpitta@uniroma2.it>
+#
+# 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.
+#
+
+import os
+import re
+import sys
+import json
+import functools
+import pytest
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+from lib.common_config import required_linux_kernel_version
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def build_topo(tgen):
+ tgen.add_router("r1")
+ tgen.add_router("r2")
+ tgen.add_router("ce1")
+ tgen.add_router("ce2")
+ tgen.add_router("ce3")
+ tgen.add_router("ce4")
+ tgen.add_router("ce5")
+ tgen.add_router("ce6")
+
+ tgen.add_link(tgen.gears["r1"], tgen.gears["r2"], "eth0", "eth0")
+ tgen.add_link(tgen.gears["ce1"], tgen.gears["r1"], "eth0", "eth1")
+ tgen.add_link(tgen.gears["ce2"], tgen.gears["r2"], "eth0", "eth1")
+ tgen.add_link(tgen.gears["ce3"], tgen.gears["r1"], "eth0", "eth2")
+ tgen.add_link(tgen.gears["ce4"], tgen.gears["r2"], "eth0", "eth2")
+ tgen.add_link(tgen.gears["ce5"], tgen.gears["r1"], "eth0", "eth3")
+ tgen.add_link(tgen.gears["ce6"], tgen.gears["r2"], "eth0", "eth3")
+
+
+def setup_module(mod):
+ result = required_linux_kernel_version("5.14")
+ if result is not True:
+ pytest.skip("Kernel requirements are not met")
+
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+ for rname, router in tgen.routers().items():
+ router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname))
+ router.load_config(TopoRouter.RD_ZEBRA,
+ os.path.join(CWD, '{}/zebra.conf'.format(rname)))
+ router.load_config(TopoRouter.RD_BGP,
+ os.path.join(CWD, '{}/bgpd.conf'.format(rname)))
+
+ tgen.gears["r1"].run("sysctl net.vrf.strict_mode=1")
+ tgen.gears["r1"].run("ip link add vrf10 type vrf table 10")
+ tgen.gears["r1"].run("ip link set vrf10 up")
+ tgen.gears["r1"].run("ip link add vrf20 type vrf table 20")
+ tgen.gears["r1"].run("ip link set vrf20 up")
+ tgen.gears["r1"].run("ip link set eth1 master vrf10")
+ tgen.gears["r1"].run("ip link set eth2 master vrf10")
+ tgen.gears["r1"].run("ip link set eth3 master vrf20")
+
+ tgen.gears["r2"].run("sysctl net.vrf.strict_mode=1")
+ tgen.gears["r2"].run("ip link add vrf10 type vrf table 10")
+ tgen.gears["r2"].run("ip link set vrf10 up")
+ tgen.gears["r2"].run("ip link add vrf20 type vrf table 20")
+ tgen.gears["r2"].run("ip link set vrf20 up")
+ tgen.gears["r2"].run("ip link set eth1 master vrf10")
+ tgen.gears["r2"].run("ip link set eth2 master vrf20")
+ tgen.gears["r2"].run("ip link set eth3 master vrf20")
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def open_json_file(filename):
+ try:
+ with open(filename, "r") as f:
+ return json.load(f)
+ except IOError:
+ assert False, "Could not read file {}".format(filename)
+
+
+def check_ping4(name, dest_addr, expect_connected):
+ def _check(name, dest_addr, match):
+ tgen = get_topogen()
+ output = tgen.gears[name].run("ping {} -c 1 -w 1".format(dest_addr))
+ logger.info(output)
+ assert match in output, "ping fail"
+
+ match = "{} packet loss".format("0%" if expect_connected else "100%")
+ logger.info("[+] check {} {} {}".format(name, dest_addr, match))
+ tgen = get_topogen()
+ func = functools.partial(_check, name, dest_addr, match)
+ success, result = topotest.run_and_expect(func, None, count=10, wait=0.5)
+ assert result is None, "Failed"
+
+
+def check_ping6(name, dest_addr, expect_connected):
+ def _check(name, dest_addr, match):
+ tgen = get_topogen()
+ output = tgen.gears[name].run("ping6 {} -c 1 -w 1".format(dest_addr))
+ logger.info(output)
+ if match not in output:
+ return "ping fail"
+
+ match = "{} packet loss".format("0%" if expect_connected else "100%")
+ logger.info("[+] check {} {} {}".format(name, dest_addr, match))
+ tgen = get_topogen()
+ func = functools.partial(_check, name, dest_addr, match)
+ success, result = topotest.run_and_expect(func, None, count=10, wait=1)
+ assert result is None, "Failed"
+
+
+def check_rib(name, cmd, expected_file):
+ def _check(name, dest_addr, match):
+ logger.info("polling")
+ tgen = get_topogen()
+ router = tgen.gears[name]
+ output = json.loads(router.vtysh_cmd(cmd))
+ expected = open_json_file("{}/{}".format(CWD, expected_file))
+ return topotest.json_cmp(output, expected)
+
+ logger.info("[+] check {} \"{}\" {}".format(name, cmd, expected_file))
+ tgen = get_topogen()
+ func = functools.partial(_check, name, cmd, expected_file)
+ success, result = topotest.run_and_expect(func, None, count=10, wait=0.5)
+ assert result is None, "Failed"
+
+
+def test_rib():
+ check_rib("r1", "show bgp ipv4 vpn json", "r1/vpnv4_rib.json")
+ check_rib("r2", "show bgp ipv4 vpn json", "r2/vpnv4_rib.json")
+ check_rib("r1", "show ip route vrf vrf10 json", "r1/vrf10v4_rib.json")
+ check_rib("r1", "show ip route vrf vrf20 json", "r1/vrf20v4_rib.json")
+ check_rib("r2", "show ip route vrf vrf10 json", "r2/vrf10v4_rib.json")
+ check_rib("r2", "show ip route vrf vrf20 json", "r2/vrf20v4_rib.json")
+ check_rib("ce1", "show ip route json", "ce1/ip_rib.json")
+ check_rib("ce2", "show ip route json", "ce2/ip_rib.json")
+ check_rib("ce3", "show ip route json", "ce3/ip_rib.json")
+ check_rib("ce4", "show ip route json", "ce4/ip_rib.json")
+ check_rib("ce5", "show ip route json", "ce5/ip_rib.json")
+ check_rib("ce6", "show ip route json", "ce6/ip_rib.json")
+
+ check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib.json")
+ check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib.json")
+ check_rib("r1", "show ipv6 route vrf vrf10 json", "r1/vrf10v6_rib.json")
+ check_rib("r1", "show ipv6 route vrf vrf20 json", "r1/vrf20v6_rib.json")
+ check_rib("r2", "show ipv6 route vrf vrf10 json", "r2/vrf10v6_rib.json")
+ check_rib("r2", "show ipv6 route vrf vrf20 json", "r2/vrf20v6_rib.json")
+ check_rib("ce1", "show ipv6 route json", "ce1/ipv6_rib.json")
+ check_rib("ce2", "show ipv6 route json", "ce2/ipv6_rib.json")
+ check_rib("ce3", "show ipv6 route json", "ce3/ipv6_rib.json")
+ check_rib("ce4", "show ipv6 route json", "ce4/ipv6_rib.json")
+ check_rib("ce5", "show ipv6 route json", "ce5/ipv6_rib.json")
+ check_rib("ce6", "show ipv6 route json", "ce6/ipv6_rib.json")
+
+
+def test_ping():
+ check_ping4("ce1", "192.168.2.2", True)
+ check_ping4("ce1", "192.168.3.2", True)
+ check_ping4("ce1", "192.168.4.2", False)
+ check_ping4("ce1", "192.168.5.2", False)
+ check_ping4("ce1", "192.168.6.2", False)
+ check_ping4("ce4", "192.168.1.2", False)
+ check_ping4("ce4", "192.168.2.2", False)
+ check_ping4("ce4", "192.168.3.2", False)
+ check_ping4("ce4", "192.168.5.2", True)
+ check_ping4("ce4", "192.168.6.2", True)
+
+ check_ping6("ce1", "2001:2::2", True)
+ check_ping6("ce1", "2001:3::2", True)
+ check_ping6("ce1", "2001:4::2", False)
+ check_ping6("ce1", "2001:5::2", False)
+ check_ping6("ce1", "2001:6::2", False)
+ check_ping6("ce4", "2001:1::2", False)
+ check_ping6("ce4", "2001:2::2", False)
+ check_ping6("ce4", "2001:3::2", False)
+ check_ping6("ce4", "2001:5::2", True)
+ check_ping6("ce4", "2001:6::2", True)
+
+
+def test_bgp_sid_vpn_export_disable():
+ check_ping4("ce1", "192.168.2.2", True)
+ check_ping6("ce1", "2001:2::2", True)
+ get_topogen().gears["r1"].vtysh_cmd(
+ """
+ configure terminal
+ router bgp 1 vrf vrf10
+ segment-routing srv6
+ no sid vpn per-vrf export
+ """
+ )
+ check_rib("r1", "show bgp ipv4 vpn json", "r1/vpnv4_rib_sid_vpn_export_disabled.json")
+ check_rib("r2", "show bgp ipv4 vpn json", "r2/vpnv4_rib_sid_vpn_export_disabled.json")
+ check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_sid_vpn_export_disabled.json")
+ check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_sid_vpn_export_disabled.json")
+ check_ping4("ce1", "192.168.2.2", False)
+ check_ping6("ce1", "2001:2::2", False)
+
+
+def test_bgp_sid_vpn_export_reenable():
+ check_ping4("ce1", "192.168.2.2", False)
+ check_ping6("ce1", "2001:2::2", False)
+ get_topogen().gears["r1"].vtysh_cmd(
+ """
+ configure terminal
+ router bgp 1 vrf vrf10
+ segment-routing srv6
+ sid vpn per-vrf export auto
+ """
+ )
+ check_rib("r1", "show bgp ipv4 vpn json", "r1/vpnv4_rib_sid_vpn_export_reenabled.json")
+ check_rib("r2", "show bgp ipv4 vpn json", "r2/vpnv4_rib_sid_vpn_export_reenabled.json")
+ check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_sid_vpn_export_reenabled.json")
+ check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_sid_vpn_export_reenabled.json")
+ check_ping4("ce1", "192.168.2.2", True)
+ check_ping6("ce1", "2001:2::2", True)
+
+
+def test_locator_delete():
+ check_ping4("ce1", "192.168.2.2", True)
+ check_ping6("ce1", "2001:2::2", True)
+ get_topogen().gears["r1"].vtysh_cmd(
+ """
+ configure terminal
+ segment-routing
+ srv6
+ locators
+ no locator loc1
+ """
+ )
+ check_rib("r1", "show bgp ipv4 vpn json", "r1/vpnv4_rib_locator_deleted.json")
+ check_rib("r2", "show bgp ipv4 vpn json", "r2/vpnv4_rib_locator_deleted.json")
+ check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_locator_deleted.json")
+ check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_locator_deleted.json")
+ check_ping4("ce1", "192.168.2.2", False)
+ check_ping6("ce1", "2001:2::2", False)
+
+
+def test_locator_recreate():
+ check_ping4("ce1", "192.168.2.2", False)
+ check_ping6("ce1", "2001:2::2", False)
+ get_topogen().gears["r1"].vtysh_cmd(
+ """
+ configure terminal
+ segment-routing
+ srv6
+ locators
+ locator loc1
+ prefix 2001:db8:1:1::/64
+ """
+ )
+ check_rib("r1", "show bgp ipv4 vpn json", "r1/vpnv4_rib_locator_recreated.json")
+ check_rib("r2", "show bgp ipv4 vpn json", "r2/vpnv4_rib_locator_recreated.json")
+ check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_locator_recreated.json")
+ check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_locator_recreated.json")
+ check_ping4("ce1", "192.168.2.2", True)
+ check_ping6("ce1", "2001:2::2", True)
+
+
+def test_bgp_locator_unset():
+ check_ping4("ce1", "192.168.2.2", True)
+ check_ping6("ce1", "2001:2::2", True)
+ get_topogen().gears["r1"].vtysh_cmd(
+ """
+ configure terminal
+ router bgp 1
+ segment-routing srv6
+ no locator loc1
+ """
+ )
+ check_rib("r1", "show bgp ipv4 vpn json", "r1/vpnv4_rib_locator_deleted.json")
+ check_rib("r2", "show bgp ipv4 vpn json", "r2/vpnv4_rib_locator_deleted.json")
+ check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_locator_deleted.json")
+ check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_locator_deleted.json")
+ check_ping4("ce1", "192.168.2.2", False)
+ check_ping6("ce1", "2001:2::2", False)
+
+
+def test_bgp_locator_reset():
+ check_ping4("ce1", "192.168.2.2", False)
+ check_ping6("ce1", "2001:2::2", False)
+ get_topogen().gears["r1"].vtysh_cmd(
+ """
+ configure terminal
+ router bgp 1
+ segment-routing srv6
+ locator loc1
+ """
+ )
+ check_rib("r1", "show bgp ipv4 vpn json", "r1/vpnv4_rib_locator_recreated.json")
+ check_rib("r2", "show bgp ipv4 vpn json", "r2/vpnv4_rib_locator_recreated.json")
+ check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_locator_recreated.json")
+ check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_locator_recreated.json")
+ check_ping4("ce1", "192.168.2.2", True)
+ check_ping6("ce1", "2001:2::2", True)
+
+
+def test_bgp_srv6_unset():
+ check_ping4("ce1", "192.168.2.2", True)
+ check_ping6("ce1", "2001:2::2", True)
+ get_topogen().gears["r1"].vtysh_cmd(
+ """
+ configure terminal
+ router bgp 1
+ no segment-routing srv6
+ """
+ )
+ check_rib("r1", "show bgp ipv4 vpn json", "r1/vpnv4_rib_locator_deleted.json")
+ check_rib("r2", "show bgp ipv4 vpn json", "r2/vpnv4_rib_locator_deleted.json")
+ check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_locator_deleted.json")
+ check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_locator_deleted.json")
+ check_ping4("ce1", "192.168.2.2", False)
+ check_ping6("ce1", "2001:2::2", False)
+
+
+def test_bgp_srv6_reset():
+ check_ping4("ce1", "192.168.2.2", False)
+ check_ping6("ce1", "2001:2::2", False)
+ get_topogen().gears["r1"].vtysh_cmd(
+ """
+ configure terminal
+ router bgp 1
+ segment-routing srv6
+ locator loc1
+ """
+ )
+ check_rib("r1", "show bgp ipv4 vpn json", "r1/vpnv4_rib_locator_recreated.json")
+ check_rib("r2", "show bgp ipv4 vpn json", "r2/vpnv4_rib_locator_recreated.json")
+ check_rib("r1", "show bgp ipv6 vpn json", "r1/vpnv6_rib_locator_recreated.json")
+ check_rib("r2", "show bgp ipv6 vpn json", "r2/vpnv6_rib_locator_recreated.json")
+ check_ping4("ce1", "192.168.2.2", True)
+ check_ping6("ce1", "2001:2::2", True)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_suppress_fib/r1/bgp_ipv4_allowas.json b/tests/topotests/bgp_suppress_fib/r1/bgp_ipv4_allowas.json
index bc4d0f479..1a5ede276 100644
--- a/tests/topotests/bgp_suppress_fib/r1/bgp_ipv4_allowas.json
+++ b/tests/topotests/bgp_suppress_fib/r1/bgp_ipv4_allowas.json
@@ -32,7 +32,7 @@
],
"peer":{
"peerId":"10.0.0.2",
- "routerId":"10.0.0.9",
+ "routerId":"60.0.0.1",
"type":"external"
}
}
diff --git a/tests/topotests/bgp_suppress_fib/r2/bgp_ipv4_allowas.json b/tests/topotests/bgp_suppress_fib/r2/bgp_ipv4_allowas.json
index 16561ce83..4a35abfd6 100644
--- a/tests/topotests/bgp_suppress_fib/r2/bgp_ipv4_allowas.json
+++ b/tests/topotests/bgp_suppress_fib/r2/bgp_ipv4_allowas.json
@@ -61,7 +61,7 @@
],
"peer":{
"peerId":"0.0.0.0",
- "routerId":"10.0.0.9"
+ "routerId":"60.0.0.1"
}
}
]
diff --git a/tests/topotests/bgp_suppress_fib/r2/bgpd.conf b/tests/topotests/bgp_suppress_fib/r2/bgpd.conf
index ebef2012a..010e86aad 100644
--- a/tests/topotests/bgp_suppress_fib/r2/bgpd.conf
+++ b/tests/topotests/bgp_suppress_fib/r2/bgpd.conf
@@ -7,3 +7,5 @@ router bgp 2
bgp suppress-fib-pending
neighbor 10.0.0.1 remote-as 1
neighbor 10.0.0.10 remote-as 3
+ address-family ipv4 uni
+ network 60.0.0.0/24 \ No newline at end of file
diff --git a/tests/topotests/bgp_suppress_fib/r2/zebra.conf b/tests/topotests/bgp_suppress_fib/r2/zebra.conf
index 443fffc70..6e8bce045 100644
--- a/tests/topotests/bgp_suppress_fib/r2/zebra.conf
+++ b/tests/topotests/bgp_suppress_fib/r2/zebra.conf
@@ -1,4 +1,7 @@
!
+interface lo
+ ip address 60.0.0.1/24
+!
interface r2-eth0
ip address 10.0.0.2/30
!
diff --git a/tests/topotests/bgp_suppress_fib/r3/v4_route3.json b/tests/topotests/bgp_suppress_fib/r3/v4_route3.json
new file mode 100644
index 000000000..ab8c3aa5e
--- /dev/null
+++ b/tests/topotests/bgp_suppress_fib/r3/v4_route3.json
@@ -0,0 +1,23 @@
+{
+ "60.0.0.0/24":[
+ {
+ "prefix":"60.0.0.0/24",
+ "protocol":"bgp",
+ "selected":true,
+ "destSelected":true,
+ "distance":20,
+ "metric":0,
+ "installed":true,
+ "table":254,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.0.9",
+ "afi":"ipv4",
+ "interfaceName":"r3-eth0",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py b/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py
index 2c87d9d7b..96a294cae 100644
--- a/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py
+++ b/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py
@@ -84,8 +84,6 @@ def test_bgp_route():
r3 = tgen.gears["r3"]
- sleep(5)
-
json_file = "{}/r3/v4_route.json".format(CWD)
expected = json.loads(open(json_file).read())
@@ -95,7 +93,7 @@ def test_bgp_route():
"show ip route 40.0.0.0 json",
expected,
)
- _, result = topotest.run_and_expect(test_func, None, count=2, wait=0.5)
+ _, result = topotest.run_and_expect(test_func, None, count=20, wait=0.5)
assertmsg = '"r3" JSON output mismatches'
assert result is None, assertmsg
@@ -112,6 +110,16 @@ def test_bgp_route():
assertmsg = '"r3" JSON output mismatches'
assert result is None, assertmsg
+ json_file = "{}/r3/v4_route3.json".format(CWD)
+ expected = json.loads(open(json_file).read())
+
+ test_func = partial(
+ topotest.router_json_cmp,
+ r3,
+ "show ip route 10.0.0.3 json",
+ expected,
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=3, wait=0.5)
def test_bgp_better_admin_won():
"A better Admin distance protocol may come along and knock us out"
diff --git a/tests/topotests/cspf_topo1/r1/zebra.conf b/tests/topotests/cspf_topo1/r1/zebra.conf
index 3aa0cad43..3b615b0cb 100644
--- a/tests/topotests/cspf_topo1/r1/zebra.conf
+++ b/tests/topotests/cspf_topo1/r1/zebra.conf
@@ -10,6 +10,7 @@ interface r1-eth0
link-params
metric 20
delay 10000
+ max-bw 10e+10
ava-bw 1.25e+08
enable
exit-link-params
diff --git a/tests/topotests/cspf_topo1/r2/zebra.conf b/tests/topotests/cspf_topo1/r2/zebra.conf
index 1cc37ba12..55d9563b6 100644
--- a/tests/topotests/cspf_topo1/r2/zebra.conf
+++ b/tests/topotests/cspf_topo1/r2/zebra.conf
@@ -37,6 +37,7 @@ interface r2-eth3
link-params
metric 25
delay 25000
+ max-bw 10e+10
use-bw 1.25e+8
enable
exit-link-params
diff --git a/tests/topotests/cspf_topo1/reference/sharp-ted.json b/tests/topotests/cspf_topo1/reference/sharp-ted.json
index d3d1f9e40..da240e87a 100644
--- a/tests/topotests/cspf_topo1/reference/sharp-ted.json
+++ b/tests/topotests/cspf_topo1/reference/sharp-ted.json
@@ -64,32 +64,32 @@
"te-metric":10,
"local-address-v6":"2001:db8:1::1:1",
"remote-address-v6":"2001:db8:1::1:2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":20000
@@ -107,32 +107,32 @@
"te-metric":10,
"local-address-v6":"2001:db8:1::1:2",
"remote-address-v6":"2001:db8:1::1:1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":20000
@@ -150,32 +150,32 @@
"te-metric":40,
"local-address-v6":"2001:db8:3::3:2",
"remote-address-v6":"2001:db8:3::3:3",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":40000
@@ -194,32 +194,32 @@
"admin-group":32,
"local-address-v6":"2001:db8:3::3:3",
"remote-address-v6":"2001:db8:3::3:2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":25000
@@ -237,32 +237,32 @@
"te-metric":10,
"local-address-v6":"2001:db8:5::3:4",
"remote-address-v6":"2001:db8:5::4:3",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":10000
@@ -286,32 +286,32 @@
"te-metric":10,
"local-address-v6":"2001:db8:5::4:3",
"remote-address-v6":"2001:db8:5::3:4",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":10000
@@ -329,32 +329,32 @@
"te-metric":20,
"local-address":"10.0.0.1",
"remote-address":"10.0.0.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":99999997952,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":10000,
@@ -373,32 +373,32 @@
"te-metric":20,
"local-address":"10.0.0.2",
"remote-address":"10.0.0.1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":10000
@@ -416,32 +416,32 @@
"te-metric":10,
"local-address":"10.0.1.1",
"remote-address":"10.0.1.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":20000
@@ -459,32 +459,32 @@
"te-metric":10,
"local-address":"10.0.1.2",
"remote-address":"10.0.1.1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":20000
@@ -502,32 +502,32 @@
"te-metric":40,
"local-address":"10.0.3.2",
"remote-address":"10.0.3.3",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":40000
@@ -546,32 +546,32 @@
"admin-group":32,
"local-address":"10.0.3.3",
"remote-address":"10.0.3.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":25000
@@ -589,32 +589,32 @@
"te-metric":25,
"local-address":"10.0.4.2",
"remote-address":"10.0.4.4",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":99999997952,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":25000,
@@ -633,32 +633,32 @@
"te-metric":40,
"local-address":"10.0.4.4",
"remote-address":"10.0.4.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":40000
diff --git a/tests/topotests/cspf_topo1/test_cspf_topo1.py b/tests/topotests/cspf_topo1/test_cspf_topo1.py
index 1b71ac3a1..220ec4976 100644
--- a/tests/topotests/cspf_topo1/test_cspf_topo1.py
+++ b/tests/topotests/cspf_topo1/test_cspf_topo1.py
@@ -169,13 +169,19 @@ def compare_cspf_output(tgen, rname, fileref, src, dst, cost, bw=""):
filename = "{}/reference/{}".format(CWD, fileref)
expected = open(filename).read()
- command = "show sharp cspf source {} destination {} {} {}".format(src, dst, cost, bw)
+ command = "show sharp cspf source {} destination {} {} {}".format(
+ src, dst, cost, bw
+ )
# Run test function until we get an result. Wait at most 60 seconds.
- test_func = partial(topotest.router_output_cmp, tgen.gears[rname], command, expected)
+ test_func = partial(
+ topotest.router_output_cmp, tgen.gears[rname], command, expected
+ )
result, diff = topotest.run_and_expect(test_func, "", count=2, wait=2)
- assert result, "CSPF output mismatches the expected result on {}:\n{}".format(rname, diff)
-
+ assert result, "CSPF output mismatches the expected result on {}:\n{}".format(
+ rname, diff
+ )
+
def setup_testcase(msg):
"Setup test case"
@@ -207,10 +213,24 @@ def test_step2():
tgen = setup_testcase("Step2: CSPF(r1, r4, IPv4)")
- compare_cspf_output(tgen, "r1", "cspf-ipv4-metric.txt", "10.0.0.1", "10.0.255.4", "metric 50")
- compare_cspf_output(tgen, "r1", "cspf-ipv4-te-metric.txt", "10.0.255.1", "10.0.4.4", "te-metric 50")
- compare_cspf_output(tgen, "r1", "cspf-ipv4-delay.txt", "10.0.255.1", "10.0.255.4", "delay 50000")
- compare_cspf_output(tgen, "r1", "cspf-ipv4-delay.txt", "10.0.255.1", "10.0.255.4", "delay 50000", "rsv 7 100000000")
+ compare_cspf_output(
+ tgen, "r1", "cspf-ipv4-metric.txt", "10.0.0.1", "10.0.255.4", "metric 50"
+ )
+ compare_cspf_output(
+ tgen, "r1", "cspf-ipv4-te-metric.txt", "10.0.255.1", "10.0.4.4", "te-metric 50"
+ )
+ compare_cspf_output(
+ tgen, "r1", "cspf-ipv4-delay.txt", "10.0.255.1", "10.0.255.4", "delay 50000"
+ )
+ compare_cspf_output(
+ tgen,
+ "r1",
+ "cspf-ipv4-delay.txt",
+ "10.0.255.1",
+ "10.0.255.4",
+ "delay 50000",
+ "rsv 7 1000000",
+ )
def test_step3():
@@ -218,10 +238,34 @@ def test_step3():
tgen = setup_testcase("Step2: CSPF(r1, r4, IPv6)")
- compare_cspf_output(tgen, "r1", "cspf-ipv6-metric.txt", "2001:db8:1::1:1", "2001:db8::4", "metric 50")
- compare_cspf_output(tgen, "r1", "cspf-ipv6-te-metric.txt", "2001:db8::1", "2001:db8:5::3:4", "te-metric 80")
- compare_cspf_output(tgen, "r1", "cspf-ipv6-delay.txt", "2001:db8::1", "2001:db8::4", "delay 80000")
- compare_cspf_output(tgen, "r1", "cspf-ipv6-delay.txt", "2001:db8::1", "2001:db8::4", "delay 80000", "rsv 7 100000000")
+ compare_cspf_output(
+ tgen,
+ "r1",
+ "cspf-ipv6-metric.txt",
+ "2001:db8:1::1:1",
+ "2001:db8::4",
+ "metric 50",
+ )
+ compare_cspf_output(
+ tgen,
+ "r1",
+ "cspf-ipv6-te-metric.txt",
+ "2001:db8::1",
+ "2001:db8:5::3:4",
+ "te-metric 80",
+ )
+ compare_cspf_output(
+ tgen, "r1", "cspf-ipv6-delay.txt", "2001:db8::1", "2001:db8::4", "delay 80000"
+ )
+ compare_cspf_output(
+ tgen,
+ "r1",
+ "cspf-ipv6-delay.txt",
+ "2001:db8::1",
+ "2001:db8::4",
+ "delay 80000",
+ "rsv 7 1000000",
+ )
def test_step4():
@@ -229,13 +273,33 @@ def test_step4():
tgen = setup_testcase("Step2: CSPF(r1, r4, failure)")
- compare_cspf_output(tgen, "r1", "cspf-failed.txt", "10.0.255.1", "10.0.255.4", "metric 10")
- compare_cspf_output(tgen, "r1", "cspf-failed.txt", "2001:db8::1", "2001:db8::4", "te-metric 50")
- compare_cspf_output(tgen, "r1", "cspf-failed.txt", "10.0.255.1", "10.0.255.4", "delay 5000")
- compare_cspf_output(tgen, "r1", "cspf-failed.txt", "2001:db8::1", "2001:db8::4", "delay 80000", "rsv 7 1000000000")
- compare_cspf_output(tgen, "r1", "cspf-failed-src.txt", "10.0.0.3", "10.0.255.4", "metric 10")
- compare_cspf_output(tgen, "r1", "cspf-failed-dst.txt", "10.0.0.1", "10.0.4.40", "metric 10")
- compare_cspf_output(tgen, "r1", "cspf-failed-same.txt", "10.0.0.1", "10.0.0.1", "metric 10")
+ compare_cspf_output(
+ tgen, "r1", "cspf-failed.txt", "10.0.255.1", "10.0.255.4", "metric 10"
+ )
+ compare_cspf_output(
+ tgen, "r1", "cspf-failed.txt", "2001:db8::1", "2001:db8::4", "te-metric 50"
+ )
+ compare_cspf_output(
+ tgen, "r1", "cspf-failed.txt", "10.0.255.1", "10.0.255.4", "delay 5000"
+ )
+ compare_cspf_output(
+ tgen,
+ "r1",
+ "cspf-failed.txt",
+ "2001:db8::1",
+ "2001:db8::4",
+ "delay 80000",
+ "rsv 7 10000000",
+ )
+ compare_cspf_output(
+ tgen, "r1", "cspf-failed-src.txt", "10.0.0.3", "10.0.255.4", "metric 10"
+ )
+ compare_cspf_output(
+ tgen, "r1", "cspf-failed-dst.txt", "10.0.0.1", "10.0.4.40", "metric 10"
+ )
+ compare_cspf_output(
+ tgen, "r1", "cspf-failed-same.txt", "10.0.0.1", "10.0.0.1", "metric 10"
+ )
def test_memory_leak():
diff --git a/tests/topotests/isis_lfa_topo1/rt1/bfdd.conf b/tests/topotests/isis_lfa_topo1/rt1/bfdd.conf
new file mode 100644
index 000000000..86cf68dd8
--- /dev/null
+++ b/tests/topotests/isis_lfa_topo1/rt1/bfdd.conf
@@ -0,0 +1,6 @@
+hostname rt1
+!
+bfd
+ peer 2001:db8:1000::2 multihop local-address 2001:db8:1000::1
+ !
+!
diff --git a/tests/topotests/isis_lfa_topo1/rt1/step14/show_ipv6_route.ref.diff b/tests/topotests/isis_lfa_topo1/rt1/step14/show_ipv6_route.ref.diff
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/isis_lfa_topo1/rt1/step14/show_ipv6_route.ref.diff
diff --git a/tests/topotests/isis_lfa_topo1/rt1/step15/show_ipv6_route.ref.diff b/tests/topotests/isis_lfa_topo1/rt1/step15/show_ipv6_route.ref.diff
new file mode 100644
index 000000000..a00d2d3b6
--- /dev/null
+++ b/tests/topotests/isis_lfa_topo1/rt1/step15/show_ipv6_route.ref.diff
@@ -0,0 +1,50 @@
+--- a/rt1/step14/show_ipv6_route.ref
++++ b/rt1/step15/show_ipv6_route.ref
+@@ -6,22 +6,12 @@
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+- "metric":20,
++ "metric":25,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+- "interfaceName":"eth-rt2",
+- "active":true,
+- "backupIndex":[
+- 0
+- ]
+- }
+- ],
+- "backupNexthops":[
+- {
+- "afi":"ipv6",
+ "interfaceName":"eth-rt3",
+ "active":true
+ }
+@@ -151,22 +141,12 @@
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+- "metric":25,
++ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+- "interfaceName":"eth-rt2",
+- "active":true,
+- "backupIndex":[
+- 0
+- ]
+- }
+- ],
+- "backupNexthops":[
+- {
+- "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true
+ }
diff --git a/tests/topotests/isis_lfa_topo1/rt1/step16/show_ipv6_route.ref.diff b/tests/topotests/isis_lfa_topo1/rt1/step16/show_ipv6_route.ref.diff
new file mode 100644
index 000000000..5e48511ba
--- /dev/null
+++ b/tests/topotests/isis_lfa_topo1/rt1/step16/show_ipv6_route.ref.diff
@@ -0,0 +1,53 @@
+--- a/rt1/step15/show_ipv6_route.ref
++++ b/rt1/step16/show_ipv6_route.ref
+@@ -32,16 +32,6 @@
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt3",
+- "active":true,
+- "backupIndex":[
+- 0
+- ]
+- }
+- ],
+- "backupNexthops":[
+- {
+- "afi":"ipv6",
+- "interfaceName":"eth-rt2",
+ "active":true
+ }
+ ]
+@@ -90,16 +80,6 @@
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+- "active":true,
+- "backupIndex":[
+- 0
+- ]
+- }
+- ],
+- "backupNexthops":[
+- {
+- "afi":"ipv6",
+- "interfaceName":"eth-rt2",
+ "active":true
+ }
+ ]
+@@ -119,16 +99,6 @@
+ "fib":true,
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+- "active":true,
+- "backupIndex":[
+- 0
+- ]
+- }
+- ],
+- "backupNexthops":[
+- {
+- "afi":"ipv6",
+- "interfaceName":"eth-rt2",
+ "active":true
+ }
+ ]
diff --git a/tests/topotests/isis_lfa_topo1/rt2/bfdd.conf b/tests/topotests/isis_lfa_topo1/rt2/bfdd.conf
new file mode 100644
index 000000000..40357a4d0
--- /dev/null
+++ b/tests/topotests/isis_lfa_topo1/rt2/bfdd.conf
@@ -0,0 +1,6 @@
+hostname rt2
+!
+bfd
+ peer 2001:db8:1000::1 multihop local-address 2001:db8:1000::2
+ !
+!
diff --git a/tests/topotests/isis_lfa_topo1/test_isis_lfa_topo1.py b/tests/topotests/isis_lfa_topo1/test_isis_lfa_topo1.py
index 7e902213e..f72942b60 100755
--- a/tests/topotests/isis_lfa_topo1/test_isis_lfa_topo1.py
+++ b/tests/topotests/isis_lfa_topo1/test_isis_lfa_topo1.py
@@ -55,6 +55,7 @@ import os
import sys
import pytest
import json
+import time
import tempfile
from functools import partial
@@ -128,7 +129,7 @@ def build_topo(tgen):
files = ["show_ipv6_route.ref", "show_yang_interface_isis_adjacencies.ref"]
for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6", "rt7"]:
outputs[rname] = {}
- for step in range(1, 13 + 1):
+ for step in range(1, 16 + 1):
outputs[rname][step] = {}
for file in files:
if step == 1:
@@ -174,6 +175,9 @@ def setup_module(mod):
router.load_config(
TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname))
)
+ router.load_config(
+ TopoRouter.RD_BFD, os.path.join(CWD, "/dev/null".format(rname))
+ )
tgen.start_router()
@@ -186,7 +190,7 @@ def teardown_module(mod):
tgen.stop_topology()
-def router_compare_json_output(rname, command, reference):
+def router_compare_json_output(rname, command, reference, wait=0.5, count=120):
"Compare router JSON output"
logger.info('Comparing router "%s" "%s" output', rname, command)
@@ -196,7 +200,7 @@ def router_compare_json_output(rname, command, reference):
# Run test function until we get an result. Wait at most 60 seconds.
test_func = partial(topotest.router_json_cmp, tgen.gears[rname], command, expected)
- _, diff = topotest.run_and_expect(test_func, None, count=120, wait=0.5)
+ _, diff = topotest.run_and_expect(test_func, None, count=count, wait=wait)
assertmsg = '"{}" JSON output mismatches the expected result'.format(rname)
assert diff is None, assertmsg
@@ -616,6 +620,408 @@ def test_rib_ipv6_step13():
)
+#
+# Step 14
+#
+# Action(s):
+# - Setting spf-delay-ietf init-delay of 15s
+#
+# Expected changes:
+# - No routing table change
+# - At the end of test, SPF reacts to a failure in 15s
+#
+def test_rib_ipv6_step14():
+ logger.info("Test (step 14): verify IPv6 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("Setting spf-delay-ietf init-delay of 15s")
+ tgen.net["rt1"].cmd(
+ 'vtysh -c "conf t" -c "router isis 1" -c "spf-delay-ietf init-delay 15000 short-delay 0 long-delay 0 holddown 0 time-to-learn 0"'
+ )
+
+ for rname in ["rt1"]:
+ router_compare_json_output(
+ rname,
+ "show ipv6 route isis json",
+ outputs[rname][14]["show_ipv6_route.ref"],
+ )
+
+
+#
+# Step 15
+#
+# Action(s):
+# - shut the eth-rt2 interface on rt1
+#
+# Expected changes:
+# - Route switchover of routes via eth-rt2
+#
+def test_rib_ipv6_step15():
+ logger.info("Test (step 15): verify IPv6 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("Shut the interface to rt2 from the switch side and check fast-reroute")
+ tgen.net.cmd_raises("ip link set %s down" % tgen.net["s1"].intfs[0])
+
+ for rname in ["rt1"]:
+ router_compare_json_output(
+ rname,
+ "show ipv6 route isis json",
+ outputs[rname][15]["show_ipv6_route.ref"],
+ count=2,
+ wait=0.05,
+ )
+
+
+#
+# Step 16
+#
+# Action(s): wait for the convergence and SPF computation on rt1
+#
+# Expected changes:
+# - convergence of IPv6 RIB
+#
+def test_rib_ipv6_step16():
+ logger.info("Test (step 16): verify IPv6 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("Check SPF convergence")
+
+ for rname in ["rt1"]:
+ router_compare_json_output(
+ rname,
+ "show ipv6 route isis json",
+ outputs[rname][16]["show_ipv6_route.ref"],
+ )
+
+
+#
+# Step 17
+#
+# Action(s):
+# - Unshut the interface to rt2 from the switch sid
+#
+# Expected changes:
+# - The routing table converges
+#
+def test_rib_ipv6_step17():
+ logger.info("Test (step 17): verify IPv6 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ rname = "rt1"
+
+ logger.info("Unsetting spf-delay-ietf init-delay of 15s")
+ tgen.net[rname].cmd('vtysh -c "conf t" -c "router isis 1" -c "no spf-delay-ietf"')
+
+ logger.info(
+ "Unshut the interface to rt2 from the switch side and check fast-reroute"
+ )
+ tgen.net.cmd_raises("ip link set %s up" % tgen.net["s1"].intfs[0])
+
+ logger.info("Setting spf-delay-ietf init-delay of 15s")
+ tgen.net[rname].cmd(
+ 'vtysh -c "conf t" -c "router isis 1" -c "spf-delay-ietf init-delay 15000 short-delay 0 long-delay 0 holddown 0 time-to-learn 0"'
+ )
+
+ router_compare_json_output(
+ rname,
+ "show ipv6 route isis json",
+ outputs[rname][14]["show_ipv6_route.ref"],
+ )
+
+
+#
+# Step 18
+#
+# Action(s):
+# - drop traffic between rt1 and rt2 by shutting down the bridge between
+# the routers. Interfaces on rt1 and rt2 stay up.
+#
+#
+# Expected changes:
+# - Route switchover of routes via eth-rt2
+#
+def test_rib_ipv6_step18():
+ logger.info("Test (step 18): verify IPv6 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("Drop traffic between rt1 and rt2")
+ tgen.net.cmd_raises("ip link set s1 down")
+
+ rname = "rt1"
+
+ retry = 200 + 1
+
+ while retry:
+ retry -= 1
+ output = tgen.gears[rname].vtysh_cmd("show isis neighbor json")
+ output_json = json.loads(output)
+ found = False
+ for neighbor in output_json["areas"][0]["circuits"]:
+ if "adj" in neighbor and neighbor["adj"] == "rt2":
+ found = True
+ break
+ if not found:
+ break
+ time.sleep(0.05)
+
+ assert not found, "rt2 neighbor is still present"
+
+ router_compare_json_output(
+ rname,
+ "show ipv6 route isis json",
+ outputs[rname][15]["show_ipv6_route.ref"],
+ count=2,
+ wait=0.05,
+ )
+
+
+#
+# Step 19
+#
+# Action(s): wait for the convergence and SPF computation on rt1
+#
+# Expected changes:
+# - convergence of IPv6 RIB
+#
+def test_rib_ipv6_step19():
+ logger.info("Test (step 19): verify IPv6 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("Check SPF convergence")
+
+ for rname in ["rt1"]:
+ router_compare_json_output(
+ rname,
+ "show ipv6 route isis json",
+ outputs[rname][16]["show_ipv6_route.ref"],
+ )
+
+
+#
+# Step 20
+#
+# Action(s):
+# - Unshut the switch from rt1 to rt2
+#
+# Expected changes:
+# - The routing table goes back to the nominal state
+#
+def test_rib_ipv6_step20():
+ logger.info("Test (step 20): verify IPv6 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ rname = "rt1"
+
+ logger.info("Unsetting spf-delay-ietf init-delay of 15s")
+ tgen.net[rname].cmd('vtysh -c "conf t" -c "router isis 1" -c "no spf-delay-ietf"')
+
+ logger.info(
+ "Unshut the interface to rt2 from the switch side and check fast-reroute"
+ )
+ tgen.net.cmd_raises("ip link set s1 up")
+
+ logger.info("Setting spf-delay-ietf init-delay of 15s")
+ tgen.net[rname].cmd(
+ 'vtysh -c "conf t" -c "router isis 1" -c "spf-delay-ietf init-delay 15000 short-delay 0 long-delay 0 holddown 0 time-to-learn 0"'
+ )
+
+ router_compare_json_output(
+ rname,
+ "show ipv6 route isis json",
+ outputs[rname][14]["show_ipv6_route.ref"],
+ )
+
+
+#
+# Step 21
+#
+# Action(s):
+# - clear the rt2 ISIS neighbor on rt1
+#
+# Expected changes:
+# - Route switchover of routes via eth-rt2
+#
+def test_rib_ipv6_step21():
+ logger.info("Test (step 21): verify IPv6 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ rname = "rt1"
+
+ logger.info("Clear the rt2 ISIS neighbor on rt1 and check fast-reroute")
+ tgen.gears[rname].vtysh_cmd("clear isis neighbor rt2")
+
+ router_compare_json_output(
+ rname,
+ "show ipv6 route isis json",
+ outputs[rname][15]["show_ipv6_route.ref"],
+ count=2,
+ wait=0.05,
+ )
+
+
+#
+# Step 22
+#
+# Action(s): wait for the convergence and SPF computation on rt1
+#
+# Expected changes:
+# - convergence of IPv6 RIB
+#
+def test_rib_ipv6_step22():
+ logger.info("Test (step 22): verify IPv6 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("Check SPF convergence")
+
+ for rname in ["rt1"]:
+ router_compare_json_output(
+ rname,
+ "show ipv6 route isis json",
+ outputs[rname][16]["show_ipv6_route.ref"],
+ )
+
+
+#
+# Step 23
+#
+# Action(s):
+# - Setting BFD
+#
+# Expected changes:
+# - No routing table change
+# - BFD comes up
+#
+def test_rib_ipv6_step23():
+ logger.info("Test (step 23): verify IPv6 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("Setup BFD on rt1 and rt2")
+ for rname in ["rt1", "rt2"]:
+ conf_file = os.path.join(CWD, "{}/bfdd.conf".format(rname))
+ tgen.net[rname].cmd("vtysh -f {}".format(conf_file))
+
+ rname = "rt1"
+ expect = '[{"multihop":true,"peer":"2001:db8:1000::2","local":"2001:db8:1000::1","status":"up"}]'
+ router_compare_json_output(rname, "show bfd peers json", expect)
+
+ logger.info("Set ISIS BFD")
+ tgen.net["rt1"].cmd('vtysh -c "conf t" -c "int eth-rt2" -c "isis bfd"')
+ tgen.net["rt2"].cmd('vtysh -c "conf t" -c "int eth-rt1" -c "isis bfd"')
+
+ router_compare_json_output(
+ rname,
+ "show ipv6 route isis json",
+ outputs[rname][14]["show_ipv6_route.ref"],
+ )
+
+
+#
+# Step 24
+#
+# Action(s):
+# - drop traffic between rt1 and rt2 by shutting down the bridge between
+# the routers. Interfaces on rt1 and rt2 stay up.
+#
+# Expected changes:
+# - BFD comes down before IS-IS
+# - Route switchover of routes via eth-rt2
+#
+def test_rib_ipv6_step24():
+ logger.info("Test (step 24): verify IPv6 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("Shut the interface to rt2 from the switch side and check fast-reroute")
+ tgen.net.cmd_raises("ip link set s1 down")
+
+ rname = "rt1"
+ expect = '[{"multihop":true,"peer":"2001:db8:1000::2","local":"2001:db8:1000::1","status":"down"}]'
+ router_compare_json_output(
+ rname,
+ "show bfd peers json",
+ expect,
+ count=40,
+ wait=0.05,
+ )
+
+ router_compare_json_output(
+ rname,
+ "show ipv6 route isis json",
+ outputs[rname][15]["show_ipv6_route.ref"],
+ count=4,
+ )
+
+
+#
+# Step 25
+#
+# Action(s): wait for the convergence and SPF computation on rt1
+#
+# Expected changes:
+# - convergence of IPv6 RIB
+#
+def test_rib_ipv6_step25():
+ logger.info("Test (step 25): verify IPv6 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("Check SPF convergence")
+
+ for rname in ["rt1"]:
+ router_compare_json_output(
+ rname,
+ "show ipv6 route isis json",
+ outputs[rname][16]["show_ipv6_route.ref"],
+ )
+
+
# Memory leak test template
def test_memory_leak():
"Run the memory leak test and report results."
diff --git a/tests/topotests/isis_te_topo1/r1/zebra.conf b/tests/topotests/isis_te_topo1/r1/zebra.conf
index 814d8f8c9..2e96d5c53 100644
--- a/tests/topotests/isis_te_topo1/r1/zebra.conf
+++ b/tests/topotests/isis_te_topo1/r1/zebra.conf
@@ -10,6 +10,7 @@ interface r1-eth0
link-params
metric 20
delay 10000
+ max-bw 10e+10
ava-bw 1.25e+08
enable
exit-link-params
diff --git a/tests/topotests/isis_te_topo1/r2/zebra.conf b/tests/topotests/isis_te_topo1/r2/zebra.conf
index 26b48ded7..a25b78579 100644
--- a/tests/topotests/isis_te_topo1/r2/zebra.conf
+++ b/tests/topotests/isis_te_topo1/r2/zebra.conf
@@ -31,6 +31,7 @@ interface r2-eth3
link-params
metric 30
delay 25000
+ max-bw 10e+10
use-bw 1.25e+8
enable
exit-link-params
diff --git a/tests/topotests/isis_te_topo1/reference/ted_step1.json b/tests/topotests/isis_te_topo1/reference/ted_step1.json
index 027dd806c..d7711b7e5 100644
--- a/tests/topotests/isis_te_topo1/reference/ted_step1.json
+++ b/tests/topotests/isis_te_topo1/reference/ted_step1.json
@@ -60,32 +60,32 @@
"edge-attributes":{
"local-address-v6":"2001:db8:1::1:1",
"remote-address-v6":"2001:db8:1::1:2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -101,32 +101,32 @@
"edge-attributes":{
"local-address-v6":"2001:db8:1::1:2",
"remote-address-v6":"2001:db8:1::1:1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -142,32 +142,32 @@
"edge-attributes":{
"local-address-v6":"2001:db8:3::3:2",
"remote-address-v6":"2001:db8:3::3:3",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -184,32 +184,32 @@
"admin-group":32,
"local-address-v6":"2001:db8:3::3:3",
"remote-address-v6":"2001:db8:3::3:2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -225,32 +225,32 @@
"edge-attributes":{
"local-address-v6":"2001:db8:5::3:4",
"remote-address-v6":"2001:db8:5::4:3",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
},
@@ -274,32 +274,32 @@
"te-metric":10,
"local-address-v6":"2001:db8:5::4:3",
"remote-address-v6":"2001:db8:5::3:4",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":50000
@@ -317,32 +317,32 @@
"te-metric":20,
"local-address":"10.0.0.1",
"remote-address":"10.0.0.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":99999997952,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":10000,
@@ -360,32 +360,32 @@
"edge-attributes":{
"local-address":"10.0.0.2",
"remote-address":"10.0.0.1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -401,32 +401,32 @@
"edge-attributes":{
"local-address":"10.0.1.1",
"remote-address":"10.0.1.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -442,32 +442,32 @@
"edge-attributes":{
"local-address":"10.0.1.2",
"remote-address":"10.0.1.1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -483,32 +483,32 @@
"edge-attributes":{
"local-address":"10.0.3.2",
"remote-address":"10.0.3.3",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -525,32 +525,32 @@
"admin-group":32,
"local-address":"10.0.3.3",
"remote-address":"10.0.3.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -567,32 +567,32 @@
"te-metric":30,
"local-address":"10.0.4.2",
"remote-address":"10.0.4.4",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":99999997952,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":25000,
@@ -610,32 +610,32 @@
"edge-attributes":{
"local-address":"10.0.4.4",
"remote-address":"10.0.4.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
},
diff --git a/tests/topotests/isis_te_topo1/reference/ted_step2.json b/tests/topotests/isis_te_topo1/reference/ted_step2.json
index 2e9a5ec84..7b2074b69 100644
--- a/tests/topotests/isis_te_topo1/reference/ted_step2.json
+++ b/tests/topotests/isis_te_topo1/reference/ted_step2.json
@@ -60,32 +60,32 @@
"edge-attributes":{
"local-address-v6":"2001:db8:3::3:2",
"remote-address-v6":"2001:db8:3::3:3",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -102,32 +102,32 @@
"admin-group":32,
"local-address-v6":"2001:db8:3::3:3",
"remote-address-v6":"2001:db8:3::3:2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -143,32 +143,32 @@
"edge-attributes":{
"local-address-v6":"2001:db8:5::3:4",
"remote-address-v6":"2001:db8:5::4:3",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
},
@@ -192,32 +192,32 @@
"te-metric":10,
"local-address-v6":"2001:db8:5::4:3",
"remote-address-v6":"2001:db8:5::3:4",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":50000
@@ -235,32 +235,32 @@
"te-metric":20,
"local-address":"10.0.0.1",
"remote-address":"10.0.0.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":99999997952,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":10000,
@@ -278,32 +278,32 @@
"edge-attributes":{
"local-address":"10.0.0.2",
"remote-address":"10.0.0.1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -319,32 +319,32 @@
"edge-attributes":{
"local-address":"10.0.3.2",
"remote-address":"10.0.3.3",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -361,32 +361,32 @@
"admin-group":32,
"local-address":"10.0.3.3",
"remote-address":"10.0.3.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -403,32 +403,32 @@
"te-metric":30,
"local-address":"10.0.4.2",
"remote-address":"10.0.4.4",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":99999997952,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":25000,
@@ -446,32 +446,32 @@
"edge-attributes":{
"local-address":"10.0.4.4",
"remote-address":"10.0.4.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
},
diff --git a/tests/topotests/isis_te_topo1/reference/ted_step3.json b/tests/topotests/isis_te_topo1/reference/ted_step3.json
index 5c7ccdd6a..528138477 100644
--- a/tests/topotests/isis_te_topo1/reference/ted_step3.json
+++ b/tests/topotests/isis_te_topo1/reference/ted_step3.json
@@ -61,32 +61,32 @@
"te-metric":20,
"local-address-v6":"2001:db8::1",
"remote-address-v6":"2001:db8::2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":99999997952,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":10000,
@@ -103,32 +103,32 @@
"metric":10,
"edge-attributes":{
"local-address-v6":"2001:db8::2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -144,32 +144,32 @@
"edge-attributes":{
"local-address-v6":"2001:db8:3::3:2",
"remote-address-v6":"2001:db8:3::3:3",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -186,32 +186,32 @@
"admin-group":32,
"local-address-v6":"2001:db8:3::3:3",
"remote-address-v6":"2001:db8:3::3:2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -227,32 +227,32 @@
"edge-attributes":{
"local-address-v6":"2001:db8:5::3:4",
"remote-address-v6":"2001:db8:5::4:3",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
},
@@ -276,32 +276,32 @@
"te-metric":10,
"local-address-v6":"2001:db8:5::4:3",
"remote-address-v6":"2001:db8:5::3:4",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":50000
@@ -319,32 +319,32 @@
"te-metric":20,
"local-address":"10.0.0.1",
"remote-address":"10.0.0.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":99999997952,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":10000,
@@ -362,32 +362,32 @@
"edge-attributes":{
"local-address":"10.0.0.2",
"remote-address":"10.0.0.1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -403,32 +403,32 @@
"edge-attributes":{
"local-address":"10.0.3.2",
"remote-address":"10.0.3.3",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -445,32 +445,32 @@
"admin-group":32,
"local-address":"10.0.3.3",
"remote-address":"10.0.3.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -487,32 +487,32 @@
"te-metric":30,
"local-address":"10.0.4.2",
"remote-address":"10.0.4.4",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":99999997952,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":25000,
@@ -530,32 +530,32 @@
"edge-attributes":{
"local-address":"10.0.4.4",
"remote-address":"10.0.4.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
},
diff --git a/tests/topotests/isis_te_topo1/reference/ted_step4.json b/tests/topotests/isis_te_topo1/reference/ted_step4.json
index 5c7ccdd6a..528138477 100644
--- a/tests/topotests/isis_te_topo1/reference/ted_step4.json
+++ b/tests/topotests/isis_te_topo1/reference/ted_step4.json
@@ -61,32 +61,32 @@
"te-metric":20,
"local-address-v6":"2001:db8::1",
"remote-address-v6":"2001:db8::2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":99999997952,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":10000,
@@ -103,32 +103,32 @@
"metric":10,
"edge-attributes":{
"local-address-v6":"2001:db8::2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -144,32 +144,32 @@
"edge-attributes":{
"local-address-v6":"2001:db8:3::3:2",
"remote-address-v6":"2001:db8:3::3:3",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -186,32 +186,32 @@
"admin-group":32,
"local-address-v6":"2001:db8:3::3:3",
"remote-address-v6":"2001:db8:3::3:2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -227,32 +227,32 @@
"edge-attributes":{
"local-address-v6":"2001:db8:5::3:4",
"remote-address-v6":"2001:db8:5::4:3",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
},
@@ -276,32 +276,32 @@
"te-metric":10,
"local-address-v6":"2001:db8:5::4:3",
"remote-address-v6":"2001:db8:5::3:4",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":50000
@@ -319,32 +319,32 @@
"te-metric":20,
"local-address":"10.0.0.1",
"remote-address":"10.0.0.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":99999997952,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":10000,
@@ -362,32 +362,32 @@
"edge-attributes":{
"local-address":"10.0.0.2",
"remote-address":"10.0.0.1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -403,32 +403,32 @@
"edge-attributes":{
"local-address":"10.0.3.2",
"remote-address":"10.0.3.3",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -445,32 +445,32 @@
"admin-group":32,
"local-address":"10.0.3.3",
"remote-address":"10.0.3.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -487,32 +487,32 @@
"te-metric":30,
"local-address":"10.0.4.2",
"remote-address":"10.0.4.4",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":99999997952,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":25000,
@@ -530,32 +530,32 @@
"edge-attributes":{
"local-address":"10.0.4.4",
"remote-address":"10.0.4.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
},
diff --git a/tests/topotests/isis_te_topo1/reference/ted_step5.json b/tests/topotests/isis_te_topo1/reference/ted_step5.json
index 48d475c72..72e441d18 100644
--- a/tests/topotests/isis_te_topo1/reference/ted_step5.json
+++ b/tests/topotests/isis_te_topo1/reference/ted_step5.json
@@ -61,32 +61,32 @@
"te-metric":20,
"local-address-v6":"2001:db8::1",
"remote-address-v6":"2001:db8::2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":99999997952,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":10000,
@@ -103,32 +103,32 @@
"metric":10,
"edge-attributes":{
"local-address-v6":"2001:db8::2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -144,32 +144,32 @@
"edge-attributes":{
"local-address-v6":"2001:db8:1::1:1",
"remote-address-v6":"2001:db8:1::1:2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -185,32 +185,32 @@
"edge-attributes":{
"local-address-v6":"2001:db8:1::1:2",
"remote-address-v6":"2001:db8:1::1:1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -226,32 +226,32 @@
"edge-attributes":{
"local-address-v6":"2001:db8:3::3:2",
"remote-address-v6":"2001:db8:3::3:3",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -268,32 +268,32 @@
"admin-group":32,
"local-address-v6":"2001:db8:3::3:3",
"remote-address-v6":"2001:db8:3::3:2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -309,32 +309,32 @@
"edge-attributes":{
"local-address-v6":"2001:db8:5::3:4",
"remote-address-v6":"2001:db8:5::4:3",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
},
@@ -358,32 +358,32 @@
"te-metric":10,
"local-address-v6":"2001:db8:5::4:3",
"remote-address-v6":"2001:db8:5::3:4",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":50000
@@ -401,32 +401,32 @@
"te-metric":20,
"local-address":"10.0.0.1",
"remote-address":"10.0.0.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":99999997952,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":10000,
@@ -444,32 +444,32 @@
"edge-attributes":{
"local-address":"10.0.0.2",
"remote-address":"10.0.0.1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -485,32 +485,32 @@
"edge-attributes":{
"local-address":"10.0.1.1",
"remote-address":"10.0.1.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -526,32 +526,32 @@
"edge-attributes":{
"local-address":"10.0.1.2",
"remote-address":"10.0.1.1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -567,32 +567,32 @@
"edge-attributes":{
"local-address":"10.0.3.2",
"remote-address":"10.0.3.3",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -609,32 +609,32 @@
"admin-group":32,
"local-address":"10.0.3.3",
"remote-address":"10.0.3.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -651,32 +651,32 @@
"te-metric":30,
"local-address":"10.0.4.2",
"remote-address":"10.0.4.4",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":99999997952,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":25000,
@@ -694,32 +694,32 @@
"edge-attributes":{
"local-address":"10.0.4.4",
"remote-address":"10.0.4.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
},
diff --git a/tests/topotests/isis_te_topo1/reference/ted_step6.json b/tests/topotests/isis_te_topo1/reference/ted_step6.json
index 75443a42e..a5f50c3eb 100644
--- a/tests/topotests/isis_te_topo1/reference/ted_step6.json
+++ b/tests/topotests/isis_te_topo1/reference/ted_step6.json
@@ -61,32 +61,32 @@
"te-metric":20,
"local-address-v6":"2001:db8::1",
"remote-address-v6":"2001:db8::2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":99999997952,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":10000,
@@ -103,32 +103,32 @@
"metric":10,
"edge-attributes":{
"local-address-v6":"2001:db8::2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -144,32 +144,32 @@
"edge-attributes":{
"local-address-v6":"2001:db8:1::1:1",
"remote-address-v6":"2001:db8:1::1:2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -185,32 +185,32 @@
"edge-attributes":{
"local-address-v6":"2001:db8:1::1:2",
"remote-address-v6":"2001:db8:1::1:1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -226,32 +226,32 @@
"edge-attributes":{
"local-address-v6":"2001:db8:3::3:2",
"remote-address-v6":"2001:db8:3::3:3",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -268,32 +268,32 @@
"admin-group":32,
"local-address-v6":"2001:db8:3::3:3",
"remote-address-v6":"2001:db8:3::3:2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -309,32 +309,32 @@
"edge-attributes":{
"local-address-v6":"2001:db8:5::3:4",
"remote-address-v6":"2001:db8:5::4:3",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
},
@@ -358,32 +358,32 @@
"te-metric":10,
"local-address-v6":"2001:db8:5::4:3",
"remote-address-v6":"2001:db8:5::3:4",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":50000
@@ -401,32 +401,32 @@
"te-metric":20,
"local-address":"10.0.0.1",
"remote-address":"10.0.0.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":99999997952,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":10000,
@@ -444,32 +444,32 @@
"edge-attributes":{
"local-address":"10.0.0.2",
"remote-address":"10.0.0.1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -485,32 +485,32 @@
"edge-attributes":{
"local-address":"10.0.1.1",
"remote-address":"10.0.1.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -526,32 +526,32 @@
"edge-attributes":{
"local-address":"10.0.1.2",
"remote-address":"10.0.1.1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -567,32 +567,32 @@
"edge-attributes":{
"local-address":"10.0.3.2",
"remote-address":"10.0.3.3",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -609,32 +609,32 @@
"admin-group":32,
"local-address":"10.0.3.3",
"remote-address":"10.0.3.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -651,32 +651,32 @@
"te-metric":30,
"local-address":"10.0.4.2",
"remote-address":"10.0.4.4",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":99999997952,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":25000
@@ -693,32 +693,32 @@
"edge-attributes":{
"local-address":"10.0.4.4",
"remote-address":"10.0.4.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":20000,
diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step10/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt1/step10/show_ip_route.ref.diff
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt1/step10/show_ip_route.ref.diff
diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step10/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt1/step10/show_ipv6_route.ref.diff
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt1/step10/show_ipv6_route.ref.diff
diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step10/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt1/step10/show_mpls_table.ref.diff
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt1/step10/show_mpls_table.ref.diff
diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step11/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt1/step11/show_ip_route.ref.diff
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt1/step11/show_ip_route.ref.diff
diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step11/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt1/step11/show_ipv6_route.ref.diff
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt1/step11/show_ipv6_route.ref.diff
diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step11/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt1/step11/show_mpls_table.ref.diff
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt1/step11/show_mpls_table.ref.diff
diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step12/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt1/step12/show_ip_route.ref.diff
new file mode 100644
index 000000000..a8d6e6c65
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt1/step12/show_ip_route.ref.diff
@@ -0,0 +1,19 @@
+--- a/rt1/step11/show_ip_route.ref
++++ b/rt1/step12/show_ip_route.ref
+@@ -110,16 +110,6 @@
+ "labels":[
+ 16060
+ ]
+- },
+- {
+- "fib":true,
+- "ip":"10.0.1.3",
+- "afi":"ipv4",
+- "interfaceName":"eth-sw1",
+- "active":true,
+- "labels":[
+- 16060
+- ]
+ }
+ ]
+ }
diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step12/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt1/step12/show_ipv6_route.ref.diff
new file mode 100644
index 000000000..637c59f6e
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt1/step12/show_ipv6_route.ref.diff
@@ -0,0 +1,18 @@
+--- a/rt1/step11/show_ipv6_route.ref
++++ b/rt1/step12/show_ipv6_route.ref
+@@ -105,15 +105,6 @@
+ "labels":[
+ 16061
+ ]
+- },
+- {
+- "fib":true,
+- "afi":"ipv6",
+- "interfaceName":"eth-sw1",
+- "active":true,
+- "labels":[
+- 16061
+- ]
+ }
+ ]
+ }
diff --git a/tests/topotests/isis_tilfa_topo1/rt1/step12/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt1/step12/show_mpls_table.ref.diff
new file mode 100644
index 000000000..e110bf48e
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt1/step12/show_mpls_table.ref.diff
@@ -0,0 +1,28 @@
+--- a/rt1/step11/show_mpls_table.ref
++++ b/rt1/step12/show_mpls_table.ref
+@@ -79,12 +79,6 @@
+ "type":"SR (IS-IS)",
+ "outLabel":16060,
+ "installed":true,
+- "nexthop":"10.0.1.3"
+- },
+- {
+- "type":"SR (IS-IS)",
+- "outLabel":16060,
+- "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+@@ -96,12 +90,6 @@
+ {
+ "type":"SR (IS-IS)",
+ "outLabel":16061,
+- "installed":true,
+- "interface":"eth-sw1"
+- },
+- {
+- "type":"SR (IS-IS)",
+- "outLabel":16061,
+ "installed":true,
+ "interface":"eth-sw1"
+ }
diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step10/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt2/step10/show_ip_route.ref.diff
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt2/step10/show_ip_route.ref.diff
diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step10/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt2/step10/show_ipv6_route.ref.diff
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt2/step10/show_ipv6_route.ref.diff
diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step10/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt2/step10/show_mpls_table.ref.diff
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt2/step10/show_mpls_table.ref.diff
diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step11/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt2/step11/show_ip_route.ref.diff
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt2/step11/show_ip_route.ref.diff
diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step11/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt2/step11/show_ipv6_route.ref.diff
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt2/step11/show_ipv6_route.ref.diff
diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step11/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt2/step11/show_mpls_table.ref.diff
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt2/step11/show_mpls_table.ref.diff
diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step12/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt2/step12/show_ip_route.ref.diff
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt2/step12/show_ip_route.ref.diff
diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step12/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt2/step12/show_ipv6_route.ref.diff
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt2/step12/show_ipv6_route.ref.diff
diff --git a/tests/topotests/isis_tilfa_topo1/rt2/step12/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt2/step12/show_mpls_table.ref.diff
new file mode 100644
index 000000000..84a36442d
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt2/step12/show_mpls_table.ref.diff
@@ -0,0 +1,20 @@
+--- a/rt2/step11/show_mpls_table.ref
++++ b/rt2/step12/show_mpls_table.ref
+@@ -199,7 +199,7 @@
+ "backupNexthops":[
+ {
+ "type":"SR (IS-IS)",
+- "outLabel":16060,
++ "outLabel":16500,
+ "nexthop":"10.0.1.3"
+ }
+ ]
+@@ -230,7 +230,7 @@
+ "backupNexthops":[
+ {
+ "type":"SR (IS-IS)",
+- "outLabel":16061,
++ "outLabel":16501,
+ "interface":"eth-sw1"
+ }
+ ]
diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step10/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step10/show_ip_route.ref.diff
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt3/step10/show_ip_route.ref.diff
diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step10/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step10/show_ipv6_route.ref.diff
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt3/step10/show_ipv6_route.ref.diff
diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step10/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step10/show_mpls_table.ref.diff
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt3/step10/show_mpls_table.ref.diff
diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step11/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step11/show_ip_route.ref.diff
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt3/step11/show_ip_route.ref.diff
diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step11/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step11/show_ipv6_route.ref.diff
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt3/step11/show_ipv6_route.ref.diff
diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step11/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step11/show_mpls_table.ref.diff
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt3/step11/show_mpls_table.ref.diff
diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step12/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step12/show_ip_route.ref.diff
new file mode 100644
index 000000000..8695cf848
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt3/step12/show_ip_route.ref.diff
@@ -0,0 +1,58 @@
+--- a/rt3/step11/show_ip_route.ref
++++ b/rt3/step12/show_ip_route.ref
+@@ -198,44 +198,37 @@
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+- "metric":30,
++ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+- "ip":"10.0.4.5",
++ "ip":"10.0.1.2",
+ "afi":"ipv4",
+- "interfaceName":"eth-rt5-1",
++ "interfaceName":"eth-sw1",
+ "active":true,
+- "backupIndex":[
+- 0
+- ],
+ "labels":[
+- 30060
++ 16060
+ ]
+ },
+ {
+ "fib":true,
+- "ip":"10.0.5.5",
++ "ip":"10.0.4.5",
+ "afi":"ipv4",
+- "interfaceName":"eth-rt5-2",
++ "interfaceName":"eth-rt5-1",
+ "active":true,
+- "backupIndex":[
+- 0
+- ],
+ "labels":[
+ 30060
+ ]
+- }
+- ],
+- "backupNexthops":[
++ },
+ {
+- "ip":"10.0.1.2",
++ "fib":true,
++ "ip":"10.0.5.5",
+ "afi":"ipv4",
+- "interfaceName":"eth-sw1",
++ "interfaceName":"eth-rt5-2",
+ "active":true,
+ "labels":[
+- 16060
++ 30060
+ ]
+ }
+ ]
diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step12/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step12/show_ipv6_route.ref.diff
new file mode 100644
index 000000000..661d0fe75
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt3/step12/show_ipv6_route.ref.diff
@@ -0,0 +1,45 @@
+--- a/rt3/step11/show_ipv6_route.ref
++++ b/rt3/step12/show_ipv6_route.ref
+@@ -186,7 +186,7 @@
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+- "metric":30,
++ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+@@ -194,9 +194,6 @@
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-1",
+ "active":true,
+- "backupIndex":[
+- 0
+- ],
+ "labels":[
+ 30061
+ ]
+@@ -206,23 +203,10 @@
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5-2",
+ "active":true,
+- "backupIndex":[
+- 0
+- ],
+ "labels":[
+ 30061
+ ]
+ }
+- ],
+- "backupNexthops":[
+- {
+- "afi":"ipv6",
+- "interfaceName":"eth-sw1",
+- "active":true,
+- "labels":[
+- 16061
+- ]
+- }
+ ]
+ }
+ ]
diff --git a/tests/topotests/isis_tilfa_topo1/rt3/step12/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt3/step12/show_mpls_table.ref.diff
new file mode 100644
index 000000000..30941b398
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt3/step12/show_mpls_table.ref.diff
@@ -0,0 +1,60 @@
+--- a/rt3/step11/show_mpls_table.ref
++++ b/rt3/step12/show_mpls_table.ref
+@@ -165,27 +165,8 @@
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+- "outLabel":30060,
+- "installed":true,
+- "nexthop":"10.0.5.5",
+- "backupIndex":[
+- 0
+- ]
+- },
+- {
+- "type":"SR (IS-IS)",
+- "outLabel":30060,
+- "installed":true,
+- "nexthop":"10.0.4.5",
+- "backupIndex":[
+- 0
+- ]
+- }
+- ],
+- "backupNexthops":[
+- {
+- "type":"SR (IS-IS)",
+ "outLabel":16060,
++ "installed":true,
+ "nexthop":"10.0.1.2"
+ }
+ ]
+@@ -196,27 +177,8 @@
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+- "outLabel":30061,
+- "installed":true,
+- "interface":"eth-rt5-2",
+- "backupIndex":[
+- 0
+- ]
+- },
+- {
+- "type":"SR (IS-IS)",
+- "outLabel":30061,
+- "installed":true,
+- "interface":"eth-rt5-1",
+- "backupIndex":[
+- 0
+- ]
+- }
+- ],
+- "backupNexthops":[
+- {
+- "type":"SR (IS-IS)",
+ "outLabel":16061,
++ "installed":true,
+ "interface":"eth-sw1"
+ }
+ ]
diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step10/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step10/show_ip_route.ref.diff
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt4/step10/show_ip_route.ref.diff
diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step10/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step10/show_ipv6_route.ref.diff
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt4/step10/show_ipv6_route.ref.diff
diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step10/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step10/show_mpls_table.ref.diff
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt4/step10/show_mpls_table.ref.diff
diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step11/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step11/show_ip_route.ref.diff
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt4/step11/show_ip_route.ref.diff
diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step11/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step11/show_ipv6_route.ref.diff
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt4/step11/show_ipv6_route.ref.diff
diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step11/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step11/show_mpls_table.ref.diff
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt4/step11/show_mpls_table.ref.diff
diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step12/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step12/show_ip_route.ref.diff
new file mode 100644
index 000000000..2645c5945
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt4/step12/show_ip_route.ref.diff
@@ -0,0 +1,144 @@
+--- a/rt4/step11/show_ip_route.ref
++++ b/rt4/step12/show_ip_route.ref
+@@ -160,23 +160,13 @@
+ "interfaceName":"eth-rt5",
+ "active":true,
+ "backupIndex":[
+- 0
++ 0,
++ 1
+ ],
+ "labels":[
+ 3
+ ]
+ }
+- ],
+- "backupNexthops":[
+- {
+- "ip":"10.0.7.6",
+- "afi":"ipv4",
+- "interfaceName":"eth-rt6",
+- "active":true,
+- "labels":[
+- 16500
+- ]
+- }
+ ]
+ }
+ ],
+@@ -196,24 +186,10 @@
+ "afi":"ipv4",
+ "interfaceName":"eth-rt6",
+ "active":true,
+- "backupIndex":[
+- 0
+- ],
+ "labels":[
+ 3
+ ]
+ }
+- ],
+- "backupNexthops":[
+- {
+- "ip":"10.0.6.5",
+- "afi":"ipv4",
+- "interfaceName":"eth-rt5",
+- "active":true,
+- "labels":[
+- 30060
+- ]
+- }
+ ]
+ }
+ ],
+@@ -352,19 +328,12 @@
+ "active":true,
+ "backupIndex":[
+ 0,
+- 1,
+- 2
++ 1
+ ]
+ }
+ ],
+ "backupNexthops":[
+ {
+- "ip":"10.0.7.6",
+- "afi":"ipv4",
+- "interfaceName":"eth-rt6",
+- "active":true
+- },
+- {
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+@@ -397,19 +366,12 @@
+ "active":true,
+ "backupIndex":[
+ 0,
+- 1,
+- 2
++ 1
+ ]
+ }
+ ],
+ "backupNexthops":[
+ {
+- "ip":"10.0.7.6",
+- "afi":"ipv4",
+- "interfaceName":"eth-rt6",
+- "active":true
+- },
+- {
+ "ip":"10.0.2.2",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt2-1",
+@@ -439,14 +401,6 @@
+ 0
+ ]
+ }
+- ],
+- "backupNexthops":[
+- {
+- "ip":"10.0.7.6",
+- "afi":"ipv4",
+- "interfaceName":"eth-rt6",
+- "active":true
+- }
+ ]
+ }
+ ],
+@@ -460,18 +414,7 @@
+ {
+ "ip":"10.0.7.6",
+ "afi":"ipv4",
+- "interfaceName":"eth-rt6",
+- "backupIndex":[
+- 0
+- ]
+- }
+- ],
+- "backupNexthops":[
+- {
+- "ip":"10.0.6.5",
+- "afi":"ipv4",
+- "interfaceName":"eth-rt5",
+- "active":true
++ "interfaceName":"eth-rt6"
+ }
+ ]
+ }
+@@ -492,13 +435,6 @@
+ "afi":"ipv4",
+ "interfaceName":"eth-rt5",
+ "active":true
+- },
+- {
+- "fib":true,
+- "ip":"10.0.7.6",
+- "afi":"ipv4",
+- "interfaceName":"eth-rt6",
+- "active":true
+ }
+ ]
+ }
diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step12/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step12/show_ipv6_route.ref.diff
new file mode 100644
index 000000000..37e3185ae
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt4/step12/show_ipv6_route.ref.diff
@@ -0,0 +1,50 @@
+--- a/rt4/step11/show_ipv6_route.ref
++++ b/rt4/step12/show_ipv6_route.ref
+@@ -149,23 +149,10 @@
+ "afi":"ipv6",
+ "interfaceName":"eth-rt5",
+ "active":true,
+- "backupIndex":[
+- 0
+- ],
+ "labels":[
+ 3
+ ]
+ }
+- ],
+- "backupNexthops":[
+- {
+- "afi":"ipv6",
+- "interfaceName":"eth-rt6",
+- "active":true,
+- "labels":[
+- 16501
+- ]
+- }
+ ]
+ }
+ ],
+@@ -184,23 +171,10 @@
+ "afi":"ipv6",
+ "interfaceName":"eth-rt6",
+ "active":true,
+- "backupIndex":[
+- 0
+- ],
+ "labels":[
+ 3
+ ]
+ }
+- ],
+- "backupNexthops":[
+- {
+- "afi":"ipv6",
+- "interfaceName":"eth-rt5",
+- "active":true,
+- "labels":[
+- 30061
+- ]
+- }
+ ]
+ }
+ ]
diff --git a/tests/topotests/isis_tilfa_topo1/rt4/step12/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt4/step12/show_mpls_table.ref.diff
new file mode 100644
index 000000000..186291ada
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt4/step12/show_mpls_table.ref.diff
@@ -0,0 +1,78 @@
+--- a/rt4/step11/show_mpls_table.ref
++++ b/rt4/step12/show_mpls_table.ref
+@@ -179,17 +179,7 @@
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+- "nexthop":"10.0.7.6",
+- "backupIndex":[
+- 0
+- ]
+- }
+- ],
+- "backupNexthops":[
+- {
+- "type":"SR (IS-IS)",
+- "outLabel":30060,
+- "nexthop":"10.0.6.5"
++ "nexthop":"10.0.7.6"
+ }
+ ]
+ },
+@@ -201,17 +191,7 @@
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+- "interface":"eth-rt6",
+- "backupIndex":[
+- 0
+- ]
+- }
+- ],
+- "backupNexthops":[
+- {
+- "type":"SR (IS-IS)",
+- "outLabel":30061,
+- "interface":"eth-rt5"
++ "interface":"eth-rt6"
+ }
+ ]
+ },
+@@ -223,17 +203,7 @@
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+- "nexthop":"10.0.6.5",
+- "backupIndex":[
+- 0
+- ]
+- }
+- ],
+- "backupNexthops":[
+- {
+- "type":"SR (IS-IS)",
+- "outLabel":16500,
+- "nexthop":"10.0.7.6"
++ "nexthop":"10.0.6.5"
+ }
+ ]
+ },
+@@ -245,17 +215,7 @@
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+- "interface":"eth-rt5",
+- "backupIndex":[
+- 0
+- ]
+- }
+- ],
+- "backupNexthops":[
+- {
+- "type":"SR (IS-IS)",
+- "outLabel":16501,
+- "interface":"eth-rt6"
++ "interface":"eth-rt5"
+ }
+ ]
+ }
diff --git a/tests/topotests/isis_tilfa_topo1/rt5/bfdd.conf b/tests/topotests/isis_tilfa_topo1/rt5/bfdd.conf
new file mode 100644
index 000000000..d27625ff3
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt5/bfdd.conf
@@ -0,0 +1,14 @@
+hostname rt5
+!
+#debug bfd network
+#debug bfd peer
+#debug bfd zebra
+!
+bfd
+ peer 10.0.8.6 interface eth-rt6
+ detect-multiplier 3
+ receive-interval 300
+ transmit-interval 300
+ no shutdown
+ !
+! \ No newline at end of file
diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step10/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step10/show_ip_route.ref.diff
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt5/step10/show_ip_route.ref.diff
diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step10/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step10/show_ipv6_route.ref.diff
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt5/step10/show_ipv6_route.ref.diff
diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step10/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step10/show_mpls_table.ref.diff
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt5/step10/show_mpls_table.ref.diff
diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step11/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step11/show_ip_route.ref.diff
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt5/step11/show_ip_route.ref.diff
diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step11/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step11/show_ipv6_route.ref.diff
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt5/step11/show_ipv6_route.ref.diff
diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step11/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step11/show_mpls_table.ref.diff
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt5/step11/show_mpls_table.ref.diff
diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step12/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step12/show_ip_route.ref.diff
new file mode 100644
index 000000000..3d21c0429
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt5/step12/show_ip_route.ref.diff
@@ -0,0 +1,151 @@
+--- a/rt5/step11/show_ip_route.ref
++++ b/rt5/step12/show_ip_route.ref
+@@ -159,24 +159,10 @@
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true,
+- "backupIndex":[
+- 0
+- ],
+ "labels":[
+ 3
+ ]
+ }
+- ],
+- "backupNexthops":[
+- {
+- "ip":"10.0.8.6",
+- "afi":"ipv4",
+- "interfaceName":"eth-rt6",
+- "active":true,
+- "labels":[
+- 16040
+- ]
+- }
+ ]
+ }
+ ],
+@@ -187,25 +173,11 @@
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+- "metric":20,
++ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+- "ip":"10.0.8.6",
+- "afi":"ipv4",
+- "interfaceName":"eth-rt6",
+- "active":true,
+- "backupIndex":[
+- 0
+- ],
+- "labels":[
+- 3
+- ]
+- }
+- ],
+- "backupNexthops":[
+- {
+ "ip":"10.0.6.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+@@ -276,19 +248,12 @@
+ "active":true,
+ "backupIndex":[
+ 0,
+- 1,
+- 2
++ 1
+ ]
+ }
+ ],
+ "backupNexthops":[
+ {
+- "ip":"10.0.8.6",
+- "afi":"ipv4",
+- "interfaceName":"eth-rt6",
+- "active":true
+- },
+- {
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+@@ -321,19 +286,12 @@
+ "active":true,
+ "backupIndex":[
+ 0,
+- 1,
+- 2
++ 1
+ ]
+ }
+ ],
+ "backupNexthops":[
+ {
+- "ip":"10.0.8.6",
+- "afi":"ipv4",
+- "interfaceName":"eth-rt6",
+- "active":true
+- },
+- {
+ "ip":"10.0.4.3",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt3-1",
+@@ -439,14 +397,6 @@
+ 0
+ ]
+ }
+- ],
+- "backupNexthops":[
+- {
+- "ip":"10.0.8.6",
+- "afi":"ipv4",
+- "interfaceName":"eth-rt6",
+- "active":true
+- }
+ ]
+ }
+ ],
+@@ -465,39 +415,6 @@
+ "ip":"10.0.6.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+- "active":true
+- },
+- {
+- "fib":true,
+- "ip":"10.0.8.6",
+- "afi":"ipv4",
+- "interfaceName":"eth-rt6",
+- "active":true
+- }
+- ]
+- }
+- ],
+- "10.0.8.0\/24":[
+- {
+- "prefix":"10.0.8.0\/24",
+- "protocol":"isis",
+- "distance":115,
+- "metric":20,
+- "nexthops":[
+- {
+- "ip":"10.0.8.6",
+- "afi":"ipv4",
+- "interfaceName":"eth-rt6",
+- "backupIndex":[
+- 0
+- ]
+- }
+- ],
+- "backupNexthops":[
+- {
+- "ip":"10.0.6.4",
+- "afi":"ipv4",
+- "interfaceName":"eth-rt4",
+ "active":true
+ }
+ ]
diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step12/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step12/show_ipv6_route.ref.diff
new file mode 100644
index 000000000..66a9dace8
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt5/step12/show_ipv6_route.ref.diff
@@ -0,0 +1,53 @@
+--- a/rt5/step11/show_ipv6_route.ref
++++ b/rt5/step12/show_ipv6_route.ref
+@@ -149,23 +149,10 @@
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true,
+- "backupIndex":[
+- 0
+- ],
+ "labels":[
+ 3
+ ]
+ }
+- ],
+- "backupNexthops":[
+- {
+- "afi":"ipv6",
+- "interfaceName":"eth-rt6",
+- "active":true,
+- "labels":[
+- 16041
+- ]
+- }
+ ]
+ }
+ ],
+@@ -176,25 +163,12 @@
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+- "metric":20,
++ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+- "interfaceName":"eth-rt6",
+- "active":true,
+- "backupIndex":[
+- 0
+- ],
+- "labels":[
+- 3
+- ]
+- }
+- ],
+- "backupNexthops":[
+- {
+- "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
diff --git a/tests/topotests/isis_tilfa_topo1/rt5/step12/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt5/step12/show_mpls_table.ref.diff
new file mode 100644
index 000000000..cdfc407f9
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt5/step12/show_mpls_table.ref.diff
@@ -0,0 +1,80 @@
+--- a/rt5/step11/show_mpls_table.ref
++++ b/rt5/step12/show_mpls_table.ref
+@@ -179,17 +179,7 @@
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+- "nexthop":"10.0.6.4",
+- "backupIndex":[
+- 0
+- ]
+- }
+- ],
+- "backupNexthops":[
+- {
+- "type":"SR (IS-IS)",
+- "outLabel":16040,
+- "nexthop":"10.0.8.6"
++ "nexthop":"10.0.6.4"
+ }
+ ]
+ },
+@@ -201,17 +191,7 @@
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+- "interface":"eth-rt4",
+- "backupIndex":[
+- 0
+- ]
+- }
+- ],
+- "backupNexthops":[
+- {
+- "type":"SR (IS-IS)",
+- "outLabel":16041,
+- "interface":"eth-rt6"
++ "interface":"eth-rt4"
+ }
+ ]
+ },
+@@ -221,18 +201,8 @@
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+- "outLabel":3,
+- "installed":true,
+- "nexthop":"10.0.8.6",
+- "backupIndex":[
+- 0
+- ]
+- }
+- ],
+- "backupNexthops":[
+- {
+- "type":"SR (IS-IS)",
+ "outLabel":16060,
++ "installed":true,
+ "nexthop":"10.0.6.4"
+ }
+ ]
+@@ -243,18 +213,8 @@
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+- "outLabel":3,
+- "installed":true,
+- "interface":"eth-rt6",
+- "backupIndex":[
+- 0
+- ]
+- }
+- ],
+- "backupNexthops":[
+- {
+- "type":"SR (IS-IS)",
+ "outLabel":16061,
++ "installed":true,
+ "interface":"eth-rt4"
+ }
+ ]
diff --git a/tests/topotests/isis_tilfa_topo1/rt6/bfdd.conf b/tests/topotests/isis_tilfa_topo1/rt6/bfdd.conf
new file mode 100644
index 000000000..0c8ba7268
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt6/bfdd.conf
@@ -0,0 +1,14 @@
+hostname rt6
+!
+#debug bfd network
+#debug bfd peer
+#debug bfd zebra
+!
+bfd
+ peer 10.0.8.5 interface eth-rt5
+ detect-multiplier 3
+ receive-interval 300
+ transmit-interval 300
+ no shutdown
+ !
+! \ No newline at end of file
diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step10/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step10/show_ip_route.ref.diff
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt6/step10/show_ip_route.ref.diff
diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step10/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step10/show_ipv6_route.ref.diff
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt6/step10/show_ipv6_route.ref.diff
diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step10/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step10/show_mpls_table.ref.diff
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt6/step10/show_mpls_table.ref.diff
diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step11/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step11/show_ip_route.ref.diff
new file mode 100644
index 000000000..e477e87d1
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt6/step11/show_ip_route.ref.diff
@@ -0,0 +1,125 @@
+--- a/rt6/step10/show_ip_route.ref
++++ b/rt6/step11/show_ip_route.ref
+@@ -76,25 +76,11 @@
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+- "metric":30,
++ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+- "ip":"10.0.8.5",
+- "afi":"ipv4",
+- "interfaceName":"eth-rt5",
+- "active":true,
+- "backupIndex":[
+- 0
+- ],
+- "labels":[
+- 30030
+- ]
+- }
+- ],
+- "backupNexthops":[
+- {
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+@@ -150,25 +136,11 @@
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+- "metric":20,
++ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+- "ip":"10.0.8.5",
+- "afi":"ipv4",
+- "interfaceName":"eth-rt5",
+- "active":true,
+- "backupIndex":[
+- 0
+- ],
+- "labels":[
+- 3
+- ]
+- }
+- ],
+- "backupNexthops":[
+- {
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+@@ -276,22 +248,11 @@
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+- "metric":20,
++ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+- "ip":"10.0.8.5",
+- "afi":"ipv4",
+- "interfaceName":"eth-rt5",
+- "active":true,
+- "backupIndex":[
+- 0
+- ]
+- }
+- ],
+- "backupNexthops":[
+- {
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+@@ -307,22 +268,11 @@
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+- "metric":20,
++ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+- "ip":"10.0.8.5",
+- "afi":"ipv4",
+- "interfaceName":"eth-rt5",
+- "active":true,
+- "backupIndex":[
+- 0
+- ]
+- }
+- ],
+- "backupNexthops":[
+- {
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+@@ -389,19 +339,9 @@
+ "prefix":"10.0.8.0\/24",
+ "protocol":"isis",
+ "distance":115,
+- "metric":20,
++ "metric":30,
+ "nexthops":[
+ {
+- "ip":"10.0.8.5",
+- "afi":"ipv4",
+- "interfaceName":"eth-rt5",
+- "backupIndex":[
+- 0
+- ]
+- }
+- ],
+- "backupNexthops":[
+- {
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step11/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step11/show_ipv6_route.ref.diff
new file mode 100644
index 000000000..12e0b591d
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt6/step11/show_ipv6_route.ref.diff
@@ -0,0 +1,56 @@
+--- a/rt6/step10/show_ipv6_route.ref
++++ b/rt6/step11/show_ipv6_route.ref
+@@ -72,25 +72,12 @@
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+- "metric":30,
++ "metric":40,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+- "interfaceName":"eth-rt5",
+- "active":true,
+- "backupIndex":[
+- 0
+- ],
+- "labels":[
+- 30031
+- ]
+- }
+- ],
+- "backupNexthops":[
+- {
+- "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
+@@ -142,25 +129,12 @@
+ "selected":true,
+ "destSelected":true,
+ "distance":115,
+- "metric":20,
++ "metric":30,
+ "installed":true,
+ "nexthops":[
+ {
+ "fib":true,
+ "afi":"ipv6",
+- "interfaceName":"eth-rt5",
+- "active":true,
+- "backupIndex":[
+- 0
+- ],
+- "labels":[
+- 3
+- ]
+- }
+- ],
+- "backupNexthops":[
+- {
+- "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true,
+ "labels":[
diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step11/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step11/show_mpls_table.ref.diff
new file mode 100644
index 000000000..387dcca3f
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt6/step11/show_mpls_table.ref.diff
@@ -0,0 +1,106 @@
+--- a/rt6/step10/show_mpls_table.ref
++++ b/rt6/step11/show_mpls_table.ref
+@@ -8,12 +8,6 @@
+ "outLabel":16010,
+ "installed":true,
+ "nexthop":"10.0.7.4"
+- },
+- {
+- "type":"SR (IS-IS)",
+- "outLabel":30010,
+- "installed":true,
+- "nexthop":"10.0.8.5"
+ }
+ ]
+ },
+@@ -26,12 +20,6 @@
+ "outLabel":16011,
+ "installed":true,
+ "interface":"eth-rt4"
+- },
+- {
+- "type":"SR (IS-IS)",
+- "outLabel":30011,
+- "installed":true,
+- "interface":"eth-rt5"
+ }
+ ]
+ },
+@@ -85,18 +73,8 @@
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+- "outLabel":30030,
+- "installed":true,
+- "nexthop":"10.0.8.5",
+- "backupIndex":[
+- 0
+- ]
+- }
+- ],
+- "backupNexthops":[
+- {
+- "type":"SR (IS-IS)",
+ "outLabel":16030,
++ "installed":true,
+ "nexthop":"10.0.7.4"
+ }
+ ]
+@@ -107,17 +85,6 @@
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+- "outLabel":30031,
+- "installed":true,
+- "interface":"eth-rt5",
+- "backupIndex":[
+- 0
+- ]
+- }
+- ],
+- "backupNexthops":[
+- {
+- "type":"SR (IS-IS)",
+ "outLabel":16031,
+ "interface":"eth-rt4"
+ }
+@@ -173,18 +140,8 @@
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+- "outLabel":3,
+- "installed":true,
+- "nexthop":"10.0.8.5",
+- "backupIndex":[
+- 0
+- ]
+- }
+- ],
+- "backupNexthops":[
+- {
+- "type":"SR (IS-IS)",
+ "outLabel":16500,
++ "installed":true,
+ "nexthop":"10.0.7.4"
+ }
+ ]
+@@ -195,18 +152,8 @@
+ "nexthops":[
+ {
+ "type":"SR (IS-IS)",
+- "outLabel":3,
+- "installed":true,
+- "interface":"eth-rt5",
+- "backupIndex":[
+- 0
+- ]
+- }
+- ],
+- "backupNexthops":[
+- {
+- "type":"SR (IS-IS)",
+ "outLabel":16501,
++ "installed":true,
+ "interface":"eth-rt4"
+ }
+ ]
diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step12/show_ip_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step12/show_ip_route.ref.diff
new file mode 100644
index 000000000..1086b6e70
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt6/step12/show_ip_route.ref.diff
@@ -0,0 +1,153 @@
+--- a/rt6/step12/show_ip_route.ref
++++ b/rt6/step12/show_ip_route.ref
+@@ -18,16 +18,6 @@
+ "labels":[
+ 16010
+ ]
+- },
+- {
+- "fib":true,
+- "ip":"10.0.8.5",
+- "afi":"ipv4",
+- "interfaceName":"eth-rt5",
+- "active":true,
+- "labels":[
+- 30010
+- ]
+ }
+ ]
+ }
+@@ -48,24 +38,10 @@
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true,
+- "backupIndex":[
+- 0
+- ],
+ "labels":[
+ 16020
+ ]
+ }
+- ],
+- "backupNexthops":[
+- {
+- "ip":"10.0.8.5",
+- "afi":"ipv4",
+- "interfaceName":"eth-rt5",
+- "active":true,
+- "labels":[
+- 30020
+- ]
+- }
+ ]
+ }
+ ],
+@@ -108,24 +84,10 @@
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true,
+- "backupIndex":[
+- 0
+- ],
+ "labels":[
+ 3
+ ]
+ }
+- ],
+- "backupNexthops":[
+- {
+- "ip":"10.0.8.5",
+- "afi":"ipv4",
+- "interfaceName":"eth-rt5",
+- "active":true,
+- "labels":[
+- 30040
+- ]
+- }
+ ]
+ }
+ ],
+@@ -168,13 +130,6 @@
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+- },
+- {
+- "fib":true,
+- "ip":"10.0.8.5",
+- "afi":"ipv4",
+- "interfaceName":"eth-rt5",
+- "active":true
+ }
+ ]
+ }
+@@ -194,17 +149,6 @@
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+- "active":true,
+- "backupIndex":[
+- 0
+- ]
+- }
+- ],
+- "backupNexthops":[
+- {
+- "ip":"10.0.8.5",
+- "afi":"ipv4",
+- "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+@@ -225,17 +169,6 @@
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+- "active":true,
+- "backupIndex":[
+- 0
+- ]
+- }
+- ],
+- "backupNexthops":[
+- {
+- "ip":"10.0.8.5",
+- "afi":"ipv4",
+- "interfaceName":"eth-rt5",
+ "active":true
+ }
+ ]
+@@ -297,13 +230,6 @@
+ "afi":"ipv4",
+ "interfaceName":"eth-rt4",
+ "active":true
+- },
+- {
+- "fib":true,
+- "ip":"10.0.8.5",
+- "afi":"ipv4",
+- "interfaceName":"eth-rt5",
+- "active":true
+ }
+ ]
+ }
+@@ -318,18 +244,7 @@
+ {
+ "ip":"10.0.7.4",
+ "afi":"ipv4",
+- "interfaceName":"eth-rt4",
+- "backupIndex":[
+- 0
+- ]
+- }
+- ],
+- "backupNexthops":[
+- {
+- "ip":"10.0.8.5",
+- "afi":"ipv4",
+- "interfaceName":"eth-rt5",
+- "active":true
++ "interfaceName":"eth-rt4"
+ }
+ ]
+ }
diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step12/show_ipv6_route.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step12/show_ipv6_route.ref.diff
new file mode 100644
index 000000000..571c66fb6
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt6/step12/show_ipv6_route.ref.diff
@@ -0,0 +1,66 @@
+--- a/rt6/step12/show_ipv6_route.ref
++++ b/rt6/step12/show_ipv6_route.ref
+@@ -17,15 +17,6 @@
+ "labels":[
+ 16011
+ ]
+- },
+- {
+- "fib":true,
+- "afi":"ipv6",
+- "interfaceName":"eth-rt5",
+- "active":true,
+- "labels":[
+- 30011
+- ]
+ }
+ ]
+ }
+@@ -45,23 +36,10 @@
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true,
+- "backupIndex":[
+- 0
+- ],
+ "labels":[
+ 16021
+ ]
+ }
+- ],
+- "backupNexthops":[
+- {
+- "afi":"ipv6",
+- "interfaceName":"eth-rt5",
+- "active":true,
+- "labels":[
+- 30021
+- ]
+- }
+ ]
+ }
+ ],
+@@ -102,23 +80,10 @@
+ "afi":"ipv6",
+ "interfaceName":"eth-rt4",
+ "active":true,
+- "backupIndex":[
+- 0
+- ],
+ "labels":[
+ 3
+ ]
+ }
+- ],
+- "backupNexthops":[
+- {
+- "afi":"ipv6",
+- "interfaceName":"eth-rt5",
+- "active":true,
+- "labels":[
+- 30041
+- ]
+- }
+ ]
+ }
+ ],
diff --git a/tests/topotests/isis_tilfa_topo1/rt6/step12/show_mpls_table.ref.diff b/tests/topotests/isis_tilfa_topo1/rt6/step12/show_mpls_table.ref.diff
new file mode 100644
index 000000000..18322f18a
--- /dev/null
+++ b/tests/topotests/isis_tilfa_topo1/rt6/step12/show_mpls_table.ref.diff
@@ -0,0 +1,78 @@
+--- a/rt6/step12/show_mpls_table.ref
++++ b/rt6/step12/show_mpls_table.ref
+@@ -31,17 +31,7 @@
+ "type":"SR (IS-IS)",
+ "outLabel":16020,
+ "installed":true,
+- "nexthop":"10.0.7.4",
+- "backupIndex":[
+- 0
+- ]
+- }
+- ],
+- "backupNexthops":[
+- {
+- "type":"SR (IS-IS)",
+- "outLabel":30020,
+- "nexthop":"10.0.8.5"
++ "nexthop":"10.0.7.4"
+ }
+ ]
+ },
+@@ -53,17 +43,7 @@
+ "type":"SR (IS-IS)",
+ "outLabel":16021,
+ "installed":true,
+- "interface":"eth-rt4",
+- "backupIndex":[
+- 0
+- ]
+- }
+- ],
+- "backupNexthops":[
+- {
+- "type":"SR (IS-IS)",
+- "outLabel":30021,
+- "interface":"eth-rt5"
++ "interface":"eth-rt4"
+ }
+ ]
+ },
+@@ -98,17 +78,7 @@
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+- "nexthop":"10.0.7.4",
+- "backupIndex":[
+- 0
+- ]
+- }
+- ],
+- "backupNexthops":[
+- {
+- "type":"SR (IS-IS)",
+- "outLabel":30040,
+- "nexthop":"10.0.8.5"
++ "nexthop":"10.0.7.4"
+ }
+ ]
+ },
+@@ -120,17 +90,7 @@
+ "type":"SR (IS-IS)",
+ "outLabel":3,
+ "installed":true,
+- "interface":"eth-rt4",
+- "backupIndex":[
+- 0
+- ]
+- }
+- ],
+- "backupNexthops":[
+- {
+- "type":"SR (IS-IS)",
+- "outLabel":30041,
+- "interface":"eth-rt5"
++ "interface":"eth-rt4"
+ }
+ ]
+ }, \ No newline at end of file
diff --git a/tests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py b/tests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py
index 07e91f1a4..5a5b9c59d 100755
--- a/tests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py
+++ b/tests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py
@@ -144,7 +144,7 @@ def build_topo(tgen):
]
for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
outputs[rname] = {}
- for step in range(1, 9 + 1):
+ for step in range(1, 12 + 1):
outputs[rname][step] = {}
for file in files:
if step == 1:
@@ -188,6 +188,9 @@ def setup_module(mod):
router.load_config(
TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname))
)
+ router.load_config(
+ TopoRouter.RD_BFD, os.path.join(CWD, "/dev/null".format(rname))
+ )
tgen.start_router()
@@ -200,7 +203,7 @@ def teardown_module(mod):
tgen.stop_topology()
-def router_compare_json_output(rname, command, reference):
+def router_compare_json_output(rname, command, reference, count=120, wait=0.5):
"Compare router JSON output"
logger.info('Comparing router "%s" "%s" output', rname, command)
@@ -210,7 +213,7 @@ def router_compare_json_output(rname, command, reference):
# Run test function until we get an result. Wait at most 60 seconds.
test_func = partial(topotest.router_json_cmp, tgen.gears[rname], command, expected)
- _, diff = topotest.run_and_expect(test_func, None, count=120, wait=0.5)
+ _, diff = topotest.run_and_expect(test_func, None, count=count, wait=wait)
assertmsg = '"{}" JSON output mismatches the expected result'.format(rname)
assert diff is None, assertmsg
@@ -740,6 +743,364 @@ def test_mpls_lib_step9():
)
+#
+# Step 10
+#
+# Action(s):
+# - Setting spf-delay-ietf init-delay of 15s
+#
+# Expected changes:
+# - No routing table change
+# - At the end of test, SPF reacts to a failure in 15s
+#
+def test_rib_ipv4_step10():
+ logger.info("Test (step 10): verify IPv4 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("Setting spf-delay-ietf init-delay of 15s")
+ tgen.net["rt6"].cmd(
+ 'vtysh -c "conf t" -c "router isis 1" -c "spf-delay-ietf init-delay 15000 short-delay 0 long-delay 0 holddown 0 time-to-learn 0"'
+ )
+
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname, "show ip route isis json", outputs[rname][10]["show_ip_route.ref"]
+ )
+
+
+def test_rib_ipv6_step10():
+ logger.info("Test (step 10): verify IPv6 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname,
+ "show ipv6 route isis json",
+ outputs[rname][10]["show_ipv6_route.ref"],
+ )
+
+
+def test_mpls_lib_step10():
+ logger.info("Test (step 10): verify MPLS LIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname, "show mpls table json", outputs[rname][10]["show_mpls_table.ref"]
+ )
+
+
+#
+# Step 11
+#
+# Action(s):
+# - shut the eth-rt5 interface on rt6
+#
+# Expected changes:
+# - Route switchover of routes via eth-rt5
+#
+def test_rt6_step11():
+ logger.info(
+ "Test (step 11): Check IPv4/6 RIB and MPLS table after a LFA switchover"
+ )
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info(
+ "Shut a rt6 interface to rt5 from the switch side and check fast-reroute"
+ )
+ tgen.net.cmd_raises("ip link set %s down" % tgen.net["s8"].intfs[1])
+
+ rname = "rt6"
+ router_compare_json_output(
+ rname,
+ "show ip route isis json",
+ outputs[rname][11]["show_ip_route.ref"],
+ count=1,
+ )
+ router_compare_json_output(
+ rname,
+ "show ipv6 route isis json",
+ outputs[rname][11]["show_ipv6_route.ref"],
+ count=1,
+ )
+ router_compare_json_output(
+ rname,
+ "show mpls table json",
+ outputs[rname][11]["show_mpls_table.ref"],
+ count=1,
+ )
+
+
+#
+# Step 12
+#
+# Action(s): wait for the convergence and SPF computation on rt6
+#
+# Expected changes:
+# - convergence of IPv4/6 RIB and MPLS table
+#
+def test_rib_ipv4_step12():
+ logger.info("Test (step 12): verify IPv4 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("Check SPF convergence")
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname,
+ "show ip route isis json",
+ outputs[rname][12]["show_ip_route.ref"],
+ )
+
+
+def test_rib_ipv6_step12():
+ logger.info("Test (step 12): verify IPv6 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname,
+ "show ipv6 route isis json",
+ outputs[rname][12]["show_ipv6_route.ref"],
+ )
+
+
+def test_mpls_lib_step12():
+ logger.info("Test (step 12): verify MPLS LIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname,
+ "show mpls table json",
+ outputs[rname][12]["show_mpls_table.ref"],
+ )
+
+
+#
+# Step 13
+#
+# Action(s):
+# - unshut the rt6 to rt5 interface
+# - Setup BFD
+#
+# Expected changes:
+# - All route tables go back to previous state situation
+# - At the end of test, next SPF is scheduled in approximatively 15s
+#
+def test_rib_ipv4_step13():
+ logger.info("Test (step 13): verify IPv4 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("Unsetting spf-delay-ietf init-delay of 15s")
+ tgen.net["rt6"].cmd('vtysh -c "conf t" -c "router isis 1" -c "no spf-delay-ietf"')
+
+ logger.info(
+ "Unshut the rt6 interface to rt5 from the switch side and check fast-reroute"
+ )
+ tgen.net.cmd_raises("ip link set %s up" % tgen.net["s8"].intfs[1])
+
+ logger.info("Setup BFD on rt5 and rt6")
+ for rname in ["rt5", "rt6"]:
+ conf_file = os.path.join(CWD, "{}/bfdd.conf".format(rname))
+ tgen.net[rname].cmd("vtysh -f {}".format(conf_file))
+
+ expect = (
+ '[{"multihop":false,"peer":"10.0.8.5","interface":"eth-rt5","status":"up"}]'
+ )
+ router_compare_json_output("rt6", "show bfd peers json", expect)
+
+ # Unset link detection. We want zebra to consider linkdow as operationaly up
+ # in order that BFD triggers LFA instead of the interface down
+
+ # reset spf-interval
+ logger.info("Set spf-interval to 15s")
+ tgen.net["rt6"].cmd(
+ 'vtysh -c "conf t" -c "router isis 1" -c "spf-delay-ietf init-delay 15000 short-delay 0 long-delay 0 holddown 0 time-to-learn 0"'
+ )
+
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname, "show ip route isis json", outputs[rname][10]["show_ip_route.ref"]
+ )
+
+ logger.info("Set ISIS BFD")
+ tgen.net["rt5"].cmd('vtysh -c "conf t" -c "int eth-rt6" -c "isis bfd"')
+ tgen.net["rt6"].cmd('vtysh -c "conf t" -c "int eth-rt5" -c "isis bfd"')
+
+
+def test_rib_ipv6_step13():
+ logger.info("Test (step 13): verify IPv6 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname,
+ "show ipv6 route isis json",
+ outputs[rname][10]["show_ipv6_route.ref"],
+ )
+
+
+def test_mpls_lib_step13():
+ logger.info("Test (step 13): verify MPLS LIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname, "show mpls table json", outputs[rname][10]["show_mpls_table.ref"]
+ )
+
+
+#
+# Step 14
+#
+# Action(s):
+# - drop traffic between rt5 and rt6 by shutting down the bridge between
+# the routers. Interfaces on rt5 and rt6 stay up.
+#
+# Expected changes:
+# - Route switchover of routes via eth-rt5
+#
+def test_rt6_step14():
+ logger.info("Test (step 14): verify IPv4/6 RIB and MPLS table")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("Drop traffic between rt5 and rt6")
+ tgen.net.cmd_raises("ip link set s8 down")
+
+ rname = "rt6"
+
+ expect = (
+ '[{"multihop":false,"peer":"10.0.8.5","interface":"eth-rt5","status":"down"}]'
+ )
+ router_compare_json_output(
+ rname,
+ "show bfd peers json",
+ expect,
+ count=40,
+ wait=0.05,
+ )
+
+ router_compare_json_output(
+ rname,
+ "show ip route isis json",
+ outputs[rname][11]["show_ip_route.ref"],
+ count=4,
+ )
+ router_compare_json_output(
+ rname,
+ "show ipv6 route isis json",
+ outputs[rname][11]["show_ipv6_route.ref"],
+ count=4,
+ )
+ router_compare_json_output(
+ rname,
+ "show mpls table json",
+ outputs[rname][11]["show_mpls_table.ref"],
+ count=4,
+ )
+
+
+#
+# Step 15
+#
+# Action(s): wait for the convergence and SPF computation on rt6
+#
+# Expected changes:
+# - convergence of IPv4/6 RIB and MPLS table
+#
+def test_rib_ipv4_step15():
+ logger.info("Test (step 15): verify IPv4 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("Check SPF convergence")
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname,
+ "show ip route isis json",
+ outputs[rname][12]["show_ip_route.ref"],
+ )
+
+
+def test_rib_ipv6_step15():
+ logger.info("Test (step 15): verify IPv6 RIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname,
+ "show ipv6 route isis json",
+ outputs[rname][12]["show_ipv6_route.ref"],
+ )
+
+
+def test_mpls_lib_step15():
+ logger.info("Test (step 15): verify MPLS LIB")
+ tgen = get_topogen()
+
+ # Skip if previous fatal error condition is raised
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6"]:
+ router_compare_json_output(
+ rname,
+ "show mpls table json",
+ outputs[rname][12]["show_mpls_table.ref"],
+ )
+
+
# Memory leak test template
def test_memory_leak():
"Run the memory leak test and report results."
diff --git a/tests/topotests/isis_topo1/test_isis_topo1.py b/tests/topotests/isis_topo1/test_isis_topo1.py
index 014722387..8b6c3772b 100644
--- a/tests/topotests/isis_topo1/test_isis_topo1.py
+++ b/tests/topotests/isis_topo1/test_isis_topo1.py
@@ -25,7 +25,7 @@
"""
test_isis_topo1.py: Test ISIS topology.
"""
-
+import datetime
import functools
import json
import os
@@ -38,6 +38,11 @@ sys.path.append(os.path.join(CWD, "../"))
# pylint: disable=C0413
from lib import topotest
+from lib.common_config import (
+ retry,
+ stop_router,
+ start_router,
+)
from lib.topogen import Topogen, TopoRouter, get_topogen
from lib.topolog import logger
@@ -248,10 +253,12 @@ def test_isis_summary_json():
for rname, router in tgen.routers().items():
logger.info("Checking router %s", rname)
json_output = tgen.gears[rname].vtysh_cmd("show isis summary json", isjson=True)
- assertmsg = "Test isis summary json failed in '{}' data '{}'".format(rname, json_output)
- assert json_output['vrf'] == "default", assertmsg
- assert json_output['areas'][0]['area'] == "1", assertmsg
- assert json_output['areas'][0]['levels'][0]['id'] != '3', assertmsg
+ assertmsg = "Test isis summary json failed in '{}' data '{}'".format(
+ rname, json_output
+ )
+ assert json_output["vrf"] == "default", assertmsg
+ assert json_output["areas"][0]["area"] == "1", assertmsg
+ assert json_output["areas"][0]["levels"][0]["id"] != "3", assertmsg
def test_isis_interface_json():
@@ -265,15 +272,29 @@ def test_isis_interface_json():
logger.info("Checking 'show isis interface json'")
for rname, router in tgen.routers().items():
logger.info("Checking router %s", rname)
- json_output = tgen.gears[rname].vtysh_cmd("show isis interface json", isjson=True)
- assertmsg = "Test isis interface json failed in '{}' data '{}'".format(rname, json_output)
- assert json_output['areas'][0]['circuits'][0]['interface']['name'] == rname+"-eth0", assertmsg
+ json_output = tgen.gears[rname].vtysh_cmd(
+ "show isis interface json", isjson=True
+ )
+ assertmsg = "Test isis interface json failed in '{}' data '{}'".format(
+ rname, json_output
+ )
+ assert (
+ json_output["areas"][0]["circuits"][0]["interface"]["name"]
+ == rname + "-eth0"
+ ), assertmsg
for rname, router in tgen.routers().items():
logger.info("Checking router %s", rname)
- json_output = tgen.gears[rname].vtysh_cmd("show isis interface detail json", isjson=True)
- assertmsg = "Test isis interface json failed in '{}' data '{}'".format(rname, json_output)
- assert json_output['areas'][0]['circuits'][0]['interface']['name'] == rname+"-eth0", assertmsg
+ json_output = tgen.gears[rname].vtysh_cmd(
+ "show isis interface detail json", isjson=True
+ )
+ assertmsg = "Test isis interface json failed in '{}' data '{}'".format(
+ rname, json_output
+ )
+ assert (
+ json_output["areas"][0]["circuits"][0]["interface"]["name"]
+ == rname + "-eth0"
+ ), assertmsg
def test_isis_neighbor_json():
@@ -284,19 +305,32 @@ def test_isis_neighbor_json():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- #tgen.mininet_cli()
+ # tgen.mininet_cli()
logger.info("Checking 'show isis neighbor json'")
for rname, router in tgen.routers().items():
logger.info("Checking router %s", rname)
- json_output = tgen.gears[rname].vtysh_cmd("show isis neighbor json", isjson=True)
- assertmsg = "Test isis neighbor json failed in '{}' data '{}'".format(rname, json_output)
- assert json_output['areas'][0]['circuits'][0]['interface'] == rname+"-eth0", assertmsg
+ json_output = tgen.gears[rname].vtysh_cmd(
+ "show isis neighbor json", isjson=True
+ )
+ assertmsg = "Test isis neighbor json failed in '{}' data '{}'".format(
+ rname, json_output
+ )
+ assert (
+ json_output["areas"][0]["circuits"][0]["interface"] == rname + "-eth0"
+ ), assertmsg
for rname, router in tgen.routers().items():
logger.info("Checking router %s", rname)
- json_output = tgen.gears[rname].vtysh_cmd("show isis neighbor detail json", isjson=True)
- assertmsg = "Test isis neighbor json failed in '{}' data '{}'".format(rname, json_output)
- assert json_output['areas'][0]['circuits'][0]['interface']['name'] == rname+"-eth0", assertmsg
+ json_output = tgen.gears[rname].vtysh_cmd(
+ "show isis neighbor detail json", isjson=True
+ )
+ assertmsg = "Test isis neighbor json failed in '{}' data '{}'".format(
+ rname, json_output
+ )
+ assert (
+ json_output["areas"][0]["circuits"][0]["interface"]["name"]
+ == rname + "-eth0"
+ ), assertmsg
def test_isis_database_json():
@@ -307,21 +341,246 @@ def test_isis_database_json():
if tgen.routers_have_failure():
pytest.skip(tgen.errors)
- #tgen.mininet_cli()
+ # tgen.mininet_cli()
logger.info("Checking 'show isis database json'")
for rname, router in tgen.routers().items():
logger.info("Checking router %s", rname)
- json_output = tgen.gears[rname].vtysh_cmd("show isis database json", isjson=True)
- assertmsg = "Test isis database json failed in '{}' data '{}'".format(rname, json_output)
- assert json_output['areas'][0]['area']['name'] == "1", assertmsg
- assert json_output['areas'][0]['levels'][0]['id'] != '3', assertmsg
+ json_output = tgen.gears[rname].vtysh_cmd(
+ "show isis database json", isjson=True
+ )
+ assertmsg = "Test isis database json failed in '{}' data '{}'".format(
+ rname, json_output
+ )
+ assert json_output["areas"][0]["area"]["name"] == "1", assertmsg
+ assert json_output["areas"][0]["levels"][0]["id"] != "3", assertmsg
for rname, router in tgen.routers().items():
logger.info("Checking router %s", rname)
- json_output = tgen.gears[rname].vtysh_cmd("show isis database detail json", isjson=True)
- assertmsg = "Test isis database json failed in '{}' data '{}'".format(rname, json_output)
- assert json_output['areas'][0]['area']['name'] == "1", assertmsg
- assert json_output['areas'][0]['levels'][0]['id'] != '3', assertmsg
+ json_output = tgen.gears[rname].vtysh_cmd(
+ "show isis database detail json", isjson=True
+ )
+ assertmsg = "Test isis database json failed in '{}' data '{}'".format(
+ rname, json_output
+ )
+ assert json_output["areas"][0]["area"]["name"] == "1", assertmsg
+ assert json_output["areas"][0]["levels"][0]["id"] != "3", assertmsg
+
+
+def test_isis_overload_on_startup():
+ "Check that overload on startup behaves as expected"
+
+ tgen = get_topogen()
+ net = get_topogen().net
+ overload_time = 120
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("Testing overload on startup behavior")
+
+ # Configure set-overload-bit on-startup on r3
+ r3 = tgen.gears["r3"]
+ r3.vtysh_cmd(
+ f"""
+ configure
+ router isis 1
+ set-overload-bit on-startup {overload_time}
+ """
+ )
+ # Restart r3
+ logger.info("Stop router")
+ stop_router(tgen, "r3")
+ logger.info("Start router")
+
+ tstamp_before_start_router = datetime.datetime.now()
+ start_router(tgen, "r3")
+ tstamp_after_start_router = datetime.datetime.now()
+ startup_router_time = (
+ tstamp_after_start_router - tstamp_before_start_router
+ ).total_seconds()
+
+ # Check that the overload bit is set in r3's LSP
+ check_lsp_overload_bit("r3", "r3.00-00", "0/0/1")
+ check_lsp_overload_bit("r1", "r3.00-00", "0/0/1")
+
+ # Attempt to unset overload bit while timer is still running
+ r3.vtysh_cmd(
+ """
+ configure
+ router isis 1
+ no set-overload-bit on-startup
+ no set-overload-bit
+ """
+ )
+
+ # Check overload bit is still set
+ check_lsp_overload_bit("r1", "r3.00-00", "0/0/1")
+
+ # Check that overload bit is unset after timer completes
+ check_lsp_overload_bit("r3", "r3.00-00", "0/0/0")
+ tstamp_after_bit_unset = datetime.datetime.now()
+ check_lsp_overload_bit("r1", "r3.00-00", "0/0/0")
+
+ # Collect time overloaded
+ time_overloaded = (
+ tstamp_after_bit_unset - tstamp_after_start_router
+ ).total_seconds()
+ logger.info(f"Time Overloaded: {time_overloaded}")
+
+ # Use time it took to startup router as lower bound
+ logger.info(
+ f"Assert that overload time falls in range: {overload_time - startup_router_time} < {time_overloaded} <= {overload_time}"
+ )
+ result = overload_time - startup_router_time < time_overloaded <= overload_time
+ assert result
+
+
+def test_isis_overload_on_startup_cancel_timer():
+ "Check that overload on startup timer is cancelled when overload bit is set/unset"
+
+ tgen = get_topogen()
+ net = get_topogen().net
+ overload_time = 90
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info(
+ "Testing overload on startup behavior with set overload bit: cancel timer"
+ )
+
+ # Configure set-overload-bit on-startup on r3
+ r3 = tgen.gears["r3"]
+ r3.vtysh_cmd(
+ f"""
+ configure
+ router isis 1
+ set-overload-bit on-startup {overload_time}
+ set-overload-bit
+ """
+ )
+ # Restart r3
+ logger.info("Stop router")
+ stop_router(tgen, "r3")
+ logger.info("Start router")
+ start_router(tgen, "r3")
+
+ # Check that the overload bit is set in r3's LSP
+ check_lsp_overload_bit("r3", "r3.00-00", "0/0/1")
+
+ # Check that overload timer is running
+ check_overload_timer("r3", True)
+
+ # Unset overload bit while timer is running
+ r3.vtysh_cmd(
+ """
+ configure
+ router isis 1
+ no set-overload-bit
+ """
+ )
+
+ # Check that overload timer is cancelled
+ check_overload_timer("r3", False)
+
+ # Check overload bit is unset
+ check_lsp_overload_bit("r3", "r3.00-00", "0/0/0")
+
+
+def test_isis_overload_on_startup_override_timer():
+ "Check that overload bit remains set after overload timer expires if overload bit is configured"
+
+ tgen = get_topogen()
+ net = get_topogen().net
+ overload_time = 60
+
+ # Don't run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info(
+ "Testing overload on startup behavior with set overload bit: override timer"
+ )
+
+ # Configure set-overload-bit on-startup on r3
+ r3 = tgen.gears["r3"]
+ r3.vtysh_cmd(
+ f"""
+ configure
+ router isis 1
+ set-overload-bit on-startup {overload_time}
+ set-overload-bit
+ """
+ )
+ # Restart r3
+ logger.info("Stop router")
+ stop_router(tgen, "r3")
+ logger.info("Start router")
+ start_router(tgen, "r3")
+
+ # Check that the overload bit is set in r3's LSP
+ check_lsp_overload_bit("r3", "r3.00-00", "0/0/1")
+
+ # Check that overload timer is running
+ check_overload_timer("r3", True)
+
+ # Check that overload timer expired
+ check_overload_timer("r3", False)
+
+ # Check overload bit is still set
+ check_lsp_overload_bit("r3", "r3.00-00", "0/0/1")
+
+
+@retry(retry_timeout=200)
+def _check_lsp_overload_bit(router, overloaded_router_lsp, att_p_ol_expected):
+ "Verfiy overload bit in router's LSP"
+
+ tgen = get_topogen()
+ router = tgen.gears[router]
+ logger.info(f"check_overload_bit {router}")
+ isis_database_output = router.vtysh_cmd(
+ "show isis database {} json".format(overloaded_router_lsp)
+ )
+
+ database_json = json.loads(isis_database_output)
+ att_p_ol = database_json["areas"][0]["levels"][1]["att-p-ol"]
+ if att_p_ol == att_p_ol_expected:
+ return True
+ return "{} peer with expected att_p_ol {} got {} ".format(
+ router.name, att_p_ol_expected, att_p_ol
+ )
+
+
+def check_lsp_overload_bit(router, overloaded_router_lsp, att_p_ol_expected):
+ "Verfiy overload bit in router's LSP"
+
+ assertmsg = _check_lsp_overload_bit(
+ router, overloaded_router_lsp, att_p_ol_expected
+ )
+ assert assertmsg is True, assertmsg
+
+
+@retry(retry_timeout=200)
+def _check_overload_timer(router, timer_expected):
+ "Verfiy overload bit in router's LSP"
+
+ tgen = get_topogen()
+ router = tgen.gears[router]
+ thread_output = router.vtysh_cmd("show thread timers")
+
+ timer_running = "set_overload_on_start_timer" in thread_output
+ if timer_running == timer_expected:
+ return True
+ return "Expected timer running status: {}".format(timer_expected)
+
+
+def check_overload_timer(router, timer_expected):
+ "Verfiy overload bit in router's LSP"
+
+ assertmsg = _check_overload_timer(router, timer_expected)
+ assert assertmsg is True, assertmsg
def test_memory_leak():
diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py
index 7ab36c4fc..a09b0b8b2 100644
--- a/tests/topotests/lib/bgp.py
+++ b/tests/topotests/lib/bgp.py
@@ -830,22 +830,36 @@ def __create_bgp_neighbor(topo, input_dict, router, addr_type, add_neigh=True):
global_connect = input_dict.get("connecttimer", 5)
for name, peer_dict in neigh_data.items():
+ remote_as = 0
for dest_link, peer in peer_dict["dest_link"].items():
+ local_asn = peer.setdefault("local_asn", {})
+ if local_asn:
+ local_as = local_asn.setdefault("local_as", 0)
+ remote_as = local_asn.setdefault("remote_as", 0)
+ no_prepend = local_asn.setdefault("no_prepend", False)
+ replace_as = local_asn.setdefault("replace_as", False)
+ if local_as == remote_as:
+ assert False is True, (
+ " Configuration Error : Router must not have "
+ "same AS-NUMBER as Local AS NUMBER"
+ )
nh_details = topo[name]
if "vrfs" in topo[router] or type(nh_details["bgp"]) is list:
for vrf_data in nh_details["bgp"]:
if "vrf" in nh_details["links"][dest_link] and "vrf" in vrf_data:
if nh_details["links"][dest_link]["vrf"] == vrf_data["vrf"]:
- remote_as = vrf_data["local_as"]
+ if not remote_as:
+ remote_as = vrf_data["local_as"]
break
else:
if "vrf" not in vrf_data:
- remote_as = vrf_data["local_as"]
- break
-
+ if not remote_as:
+ remote_as = vrf_data["local_as"]
+ break
else:
- remote_as = nh_details["bgp"]["local_as"]
+ if not remote_as:
+ remote_as = nh_details["bgp"]["local_as"]
update_source = None
@@ -890,6 +904,14 @@ def __create_bgp_neighbor(topo, input_dict, router, addr_type, add_neigh=True):
elif add_neigh:
config_data.append("{} remote-as {}".format(neigh_cxt, remote_as))
+ if local_asn and local_as:
+ cmd = "{} local-as {}".format(neigh_cxt, local_as)
+ if no_prepend:
+ cmd = "{} no-prepend".format(cmd)
+ if replace_as:
+ cmd = "{} replace-as".format(cmd)
+ config_data.append("{}".format(cmd))
+
if addr_type == "ipv6":
config_data.append("address-family ipv6 unicast")
config_data.append("{} activate".format(neigh_cxt))
@@ -2775,7 +2797,7 @@ def verify_best_path_as_per_admin_distance(
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"] == _next_hop:
+ if [nh for nh in rib_routes_json[route][0]["nexthops"] if nh['ip'] == _next_hop]:
nh_found = True
else:
errormsg = (
diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py
index 5f4c28071..737226c7f 100644
--- a/tests/topotests/lib/common_config.py
+++ b/tests/topotests/lib/common_config.py
@@ -3244,33 +3244,29 @@ def configure_interface_mac(tgen, input_dict):
return True
-def socat_send_igmp_join_traffic(
+def socat_send_mld_join(
tgen,
server,
protocol_option,
- igmp_groups,
+ mld_groups,
send_from_intf,
send_from_intf_ip=None,
port=12345,
reuseaddr=True,
- join=False,
- traffic=False,
):
"""
- API to send IGMP join using SOCAT tool
+ API to send MLD join using SOCAT tool
Parameters:
-----------
* `tgen` : Topogen object
* `server`: iperf server, from where IGMP join would be sent
* `protocol_option`: Protocol options, ex: UDP6-RECV
- * `igmp_groups`: IGMP group for which join has to be sent
+ * `mld_groups`: IGMP group for which join has to be sent
* `send_from_intf`: Interface from which join would be sent
* `send_from_intf_ip`: Interface IP, default is None
* `port`: Port to be used, default is 12345
* `reuseaddr`: True|False, bydefault True
- * `join`: If join needs to be sent
- * `traffic`: If traffic needs to be sent
returns:
--------
@@ -3280,36 +3276,32 @@ def socat_send_igmp_join_traffic(
logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
rnode = tgen.routers()[server]
- socat_cmd = "socat -u "
+ socat_args = "socat -u "
- # UDP4/TCP4/UDP6/UDP6-RECV
+ # UDP4/TCP4/UDP6/UDP6-RECV/UDP6-SEND
if protocol_option:
- socat_cmd += "{}".format(protocol_option)
+ socat_args += "{}".format(protocol_option)
if port:
- socat_cmd += ":{},".format(port)
+ socat_args += ":{},".format(port)
if reuseaddr:
- socat_cmd += "{},".format("reuseaddr")
+ socat_args += "{},".format("reuseaddr")
# Group address range to cover
- if igmp_groups:
- if not isinstance(igmp_groups, list):
- igmp_groups = [igmp_groups]
+ if mld_groups:
+ if not isinstance(mld_groups, list):
+ mld_groups = [mld_groups]
- for igmp_group in igmp_groups:
- if join:
- join_traffic_option = "ipv6-join-group"
- elif traffic:
- join_traffic_option = "ipv6-join-group-source"
+ for mld_group in mld_groups:
+ socat_cmd = socat_args
+ join_option = "ipv6-join-group"
if send_from_intf and not send_from_intf_ip:
- socat_cmd += "{}='[{}]:{}'".format(
- join_traffic_option, igmp_group, send_from_intf
- )
+ socat_cmd += "{}='[{}]:{}'".format(join_option, mld_group, send_from_intf)
else:
socat_cmd += "{}='[{}]:{}:[{}]'".format(
- join_traffic_option, igmp_group, send_from_intf, send_from_intf_ip
+ join_option, mld_group, send_from_intf, send_from_intf_ip
)
socat_cmd += " STDOUT"
@@ -3324,6 +3316,124 @@ def socat_send_igmp_join_traffic(
return True
+def socat_send_pim6_traffic(
+ tgen,
+ server,
+ protocol_option,
+ mld_groups,
+ send_from_intf,
+ port=12345,
+ multicast_hops=True,
+):
+ """
+ API to send pim6 data taffic using SOCAT tool
+
+ Parameters:
+ -----------
+ * `tgen` : Topogen object
+ * `server`: iperf server, from where IGMP join would be sent
+ * `protocol_option`: Protocol options, ex: UDP6-RECV
+ * `mld_groups`: MLD group for which join has to be sent
+ * `send_from_intf`: Interface from which join would be sent
+ * `port`: Port to be used, default is 12345
+ * `multicast_hops`: multicast-hops count, default is 255
+
+ returns:
+ --------
+ errormsg or True
+ """
+
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+ rnode = tgen.routers()[server]
+ socat_args = "socat -u STDIO "
+
+ # UDP4/TCP4/UDP6/UDP6-RECV/UDP6-SEND
+ if protocol_option:
+ socat_args += "'{}".format(protocol_option)
+
+ # Group address range to cover
+ if mld_groups:
+ if not isinstance(mld_groups, list):
+ mld_groups = [mld_groups]
+
+ for mld_group in mld_groups:
+ socat_cmd = socat_args
+ if port:
+ socat_cmd += ":[{}]:{},".format(mld_group, port)
+
+ if send_from_intf:
+ socat_cmd += "interface={0},so-bindtodevice={0},".format(send_from_intf)
+
+ if multicast_hops:
+ socat_cmd += "multicast-hops=255'"
+
+ socat_cmd += " &>{}/socat.logs &".format(tgen.logdir)
+
+ # Run socat command to send pim6 traffic
+ logger.info(
+ "[DUT: {}]: Running command: [set +m; ( while sleep 1; do date; done ) | {}]".format(
+ server, socat_cmd
+ )
+ )
+
+ # Open a shell script file and write data to it, which will be
+ # used to send pim6 traffic continously
+ traffic_shell_script = "{}/{}/traffic.sh".format(tgen.logdir, server)
+ with open("{}".format(traffic_shell_script), "w") as taffic_sh:
+ taffic_sh.write(
+ "#!/usr/bin/env bash\n( while sleep 1; do date; done ) | {}\n".format(
+ socat_cmd
+ )
+ )
+
+ rnode.run("chmod 755 {}".format(traffic_shell_script))
+ output = rnode.run("{} &> /dev/null".format(traffic_shell_script))
+
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+ return True
+
+
+def kill_socat(tgen, dut=None, action=None):
+ """
+ Killing socat process if running for any router in topology
+
+ Parameters:
+ -----------
+ * `tgen` : Topogen object
+ * `dut` : Any iperf hostname to send igmp prune
+ * `action`: to kill mld join using socat
+ to kill mld traffic using socat
+
+ Usage:
+ ------
+ kill_socat(tgen, dut ="i6", action="remove_mld_join")
+
+ """
+
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+ router_list = tgen.routers()
+ for router, rnode in router_list.items():
+ if dut is not None and router != dut:
+ continue
+
+ if action == "remove_mld_join":
+ cmd = "ps -ef | grep socat | grep UDP6-RECV | grep {}".format(router)
+ elif action == "remove_mld_traffic":
+ cmd = "ps -ef | grep socat | grep UDP6-SEND | grep {}".format(router)
+ else:
+ cmd = "ps -ef | grep socat".format(router)
+
+ awk_cmd = "awk -F' ' '{print $2}' | xargs kill -9 &>/dev/null &"
+ cmd = "{} | {}".format(cmd, awk_cmd)
+
+ logger.debug("[DUT: {}]: Running command: [{}]".format(router, cmd))
+ rnode.run(cmd)
+
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+
+
#############################################
# Verification APIs
#############################################
diff --git a/tests/topotests/lib/pim.py b/tests/topotests/lib/pim.py
index 03ab02460..7a57af7db 100644
--- a/tests/topotests/lib/pim.py
+++ b/tests/topotests/lib/pim.py
@@ -37,6 +37,7 @@ from lib.common_config import (
retry,
run_frr_cmd,
validate_ip_address,
+ get_frr_ipv6_linklocal,
)
from lib.micronet import get_exec_path
from lib.topolog import logger
@@ -48,7 +49,7 @@ CWD = os.path.dirname(os.path.realpath(__file__))
def create_pim_config(tgen, topo, input_dict=None, build=False, load_config=True):
"""
- API to configure pim/pimv6 on router
+ API to configure pim/pim6 on router
Parameters
----------
@@ -149,7 +150,7 @@ def _add_pim_rp_config(tgen, topo, input_dict, router, build, config_data_dict):
if "rp" in input_dict[router]["pim"]:
rp_data += pim_data["rp"]
- # PIMv6
+ # pim6
pim6_data = None
if "pim6" in input_dict[router]:
pim6_data = input_dict[router]["pim6"]
@@ -370,7 +371,7 @@ def create_igmp_config(tgen, topo, input_dict=None, build=False):
def create_mld_config(tgen, topo, input_dict=None, build=False):
"""
- API to configure mld for PIMv6 on router
+ API to configure mld for pim6 on router
Parameters
----------
@@ -515,6 +516,19 @@ def _enable_disable_pim_config(tgen, topo, input_dict, router, build=False):
config_data.append(cmd)
config_data.append("ip pim")
+ if "pim" in input_dict[router]:
+ if "disable" in input_dict[router]["pim"]:
+ enable_flag = False
+ interfaces = input_dict[router]["pim"]["disable"]
+
+ if type(interfaces) is not list:
+ interfaces = [interfaces]
+
+ for interface in interfaces:
+ cmd = "interface {}".format(interface)
+ config_data.append(cmd)
+ config_data.append("no ip pim")
+
if "pim6" in data and data["pim6"] == "enable":
# Loopback interfaces
if "type" in data and data["type"] == "loopback":
@@ -526,6 +540,19 @@ def _enable_disable_pim_config(tgen, topo, input_dict, router, build=False):
config_data.append(cmd)
config_data.append("ipv6 pim")
+ if "pim6" in input_dict[router]:
+ if "disable" in input_dict[router]["pim6"]:
+ enable_flag = False
+ interfaces = input_dict[router]["pim6"]["disable"]
+
+ if type(interfaces) is not list:
+ interfaces = [interfaces]
+
+ for interface in interfaces:
+ cmd = "interface {}".format(interface)
+ config_data.append(cmd)
+ config_data.append("no ipv6 pim")
+
# pim global config
if "pim" in input_dict[router]:
pim_data = input_dict[router]["pim"]
@@ -797,6 +824,134 @@ def verify_pim_neighbors(tgen, topo, dut=None, iface=None, nbr_ip=None, expected
return True
+@retry(retry_timeout=12)
+def verify_pim6_neighbors(tgen, topo, dut=None, iface=None, nbr_ip=None, expected=True):
+ """
+ Verify all pim6 neighbors are up and running, config is verified
+ using "show ipv6 pim neighbor" cli
+
+ Parameters
+ ----------
+ * `tgen`: topogen object
+ * `topo` : json file data
+ * `dut` : dut info
+ * `iface` : link for which PIM nbr need to check
+ * `nbr_ip` : neighbor ip of interface
+ * `expected` : expected results from API, by-default True
+
+ Usage
+ -----
+ result = verify_pim6_neighbors(tgen, topo, dut, iface=ens192, nbr_ip=20.1.1.2)
+
+ Returns
+ -------
+ errormsg(str) or True
+ """
+
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+ for router in tgen.routers():
+ if dut is not None and dut != router:
+ continue
+
+ rnode = tgen.routers()[router]
+ show_ip_pim_neighbor_json = rnode.vtysh_cmd(
+ "show ipv6 pim neighbor json", isjson=True
+ )
+
+ for destLink, data in topo["routers"][router]["links"].items():
+ if "type" in data and data["type"] == "loopback":
+ continue
+
+ if iface is not None and iface != data["interface"]:
+ continue
+
+ if "pim6" not in data:
+ continue
+
+ if "pim6" in data and data["pim6"] == "disable":
+ continue
+
+ if "pim6" in data and data["pim6"] == "enable":
+ local_interface = data["interface"]
+
+ if "-" in destLink:
+ # Spliting and storing destRouterLink data in tempList
+ tempList = destLink.split("-")
+
+ # destRouter
+ destLink = tempList.pop(0)
+
+ # Current Router Link
+ tempList.insert(0, router)
+ curRouter = "-".join(tempList)
+ else:
+ curRouter = router
+ if destLink not in topo["routers"]:
+ continue
+ data = topo["routers"][destLink]["links"][curRouter]
+ peer_interface = data["interface"]
+ if "type" in data and data["type"] == "loopback":
+ continue
+
+ if "pim6" not in data:
+ continue
+
+ logger.info("[DUT: %s]: Verifying PIM neighbor status:", router)
+
+ if "pim6" in data and data["pim6"] == "enable":
+ pim_nh_intf_ip = get_frr_ipv6_linklocal(tgen, destLink, peer_interface)
+
+ # Verifying PIM neighbor
+ if local_interface in show_ip_pim_neighbor_json:
+ if show_ip_pim_neighbor_json[local_interface]:
+ if (
+ show_ip_pim_neighbor_json[local_interface][pim_nh_intf_ip][
+ "neighbor"
+ ]
+ != pim_nh_intf_ip
+ ):
+ errormsg = (
+ "[DUT %s]: Local interface: %s, PIM6"
+ " neighbor check failed "
+ "Expected neighbor: %s, Found neighbor:"
+ " %s"
+ % (
+ router,
+ local_interface,
+ pim_nh_intf_ip,
+ show_ip_pim_neighbor_json[local_interface][
+ pim_nh_intf_ip
+ ]["neighbor"],
+ )
+ )
+ return errormsg
+
+ logger.info(
+ "[DUT %s]: Local interface: %s, Found"
+ " expected PIM6 neighbor %s",
+ router,
+ local_interface,
+ pim_nh_intf_ip,
+ )
+ else:
+ errormsg = (
+ "[DUT %s]: Local interface: %s, and"
+ "interface ip: %s is not found in "
+ "PIM6 neighbor " % (router, local_interface, pim_nh_intf_ip)
+ )
+ return errormsg
+ else:
+ errormsg = (
+ "[DUT %s]: Local interface: %s, is not "
+ "present in PIM6 neighbor " % (router, local_interface)
+ )
+ return errormsg
+
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+ return True
+
+
@retry(retry_timeout=40, diag_pct=0)
def verify_igmp_groups(tgen, dut, interface, group_addresses, expected=True):
"""
@@ -871,7 +1026,7 @@ def verify_igmp_groups(tgen, dut, interface, group_addresses, expected=True):
return True
-@retry(retry_timeout=60, diag_pct=0)
+@retry(retry_timeout=60, diag_pct=2)
def verify_upstream_iif(
tgen,
dut,
@@ -879,7 +1034,9 @@ def verify_upstream_iif(
src_address,
group_addresses,
joinState=None,
+ regState=None,
refCount=1,
+ addr_type="ipv4",
expected=True,
):
"""
@@ -910,7 +1067,6 @@ def verify_upstream_iif(
-------
errormsg(str) or True
"""
-
logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
if dut not in tgen.routers():
@@ -919,7 +1075,8 @@ def verify_upstream_iif(
rnode = tgen.routers()[dut]
logger.info(
- "[DUT: %s]: Verifying upstream Inbound Interface" " for IGMP groups received:",
+ "[DUT: %s]: Verifying upstream Inbound Interface"
+ " for IGMP/MLD groups received:",
dut,
)
@@ -1010,14 +1167,33 @@ def verify_upstream_iif(
)
return errormsg
+ if regState:
+ if group_addr_json[src_address]["regState"] != regState:
+ errormsg = (
+ "[DUT %s]: Verifying iif "
+ "(Inbound Interface) for (%s,%s) and"
+ " rejstate :%s [FAILED]!! "
+ " Expected: %s, Found: %s"
+ % (
+ dut,
+ src_address,
+ grp_addr,
+ group_addr_json[src_address]["regState"],
+ in_interface,
+ group_addr_json[src_address]["inboundInterface"],
+ )
+ )
+ return errormsg
+
logger.info(
"[DUT %s]: Verifying iif(Inbound Interface)"
- " for (%s,%s) and joinState is %s [PASSED]!! "
+ " for (%s,%s) and joinState is %s regstate is %s [PASSED]!! "
" Found Expected: (%s)",
dut,
src_address,
grp_addr,
group_addr_json[src_address]["joinState"],
+ group_addr_json[src_address]["regState"],
group_addr_json[src_address]["inboundInterface"],
)
if not found:
@@ -1042,7 +1218,7 @@ def verify_upstream_iif(
@retry(retry_timeout=12)
def verify_join_state_and_timer(
- tgen, dut, iif, src_address, group_addresses, expected=True
+ tgen, dut, iif, src_address, group_addresses, addr_type="ipv4", expected=True
):
"""
Verify join state is updated correctly and join timer is
@@ -1178,6 +1354,7 @@ def verify_mroutes(
oil,
return_uptime=False,
mwait=0,
+ addr_type="ipv4",
expected=True,
):
"""
@@ -1393,6 +1570,7 @@ def verify_pim_rp_info(
rp=None,
source=None,
iamrp=None,
+ addr_type="ipv4",
expected=True,
):
"""
@@ -1578,6 +1756,7 @@ def verify_pim_state(
group_addresses,
src_address=None,
installed_fl=None,
+ addr_type="ipv4",
expected=True,
):
"""
@@ -1697,7 +1876,7 @@ def verify_pim_state(
def get_pim_interface_traffic(tgen, input_dict):
"""
- get ip pim interface traffice by running
+ get ip pim interface traffic by running
"show ip pim interface traffic" cli
Parameters
@@ -1768,9 +1947,82 @@ def get_pim_interface_traffic(tgen, input_dict):
return output_dict
+def get_pim6_interface_traffic(tgen, input_dict):
+ """
+ get ipv6 pim interface traffic by running
+ "show ipv6 pim interface traffic" cli
+
+ Parameters
+ ----------
+ * `tgen`: topogen object
+ * `input_dict(dict)`: defines DUT, what and from which interfaces
+ traffic needs to be retrieved
+ Usage
+ -----
+ input_dict = {
+ "r1": {
+ "r1-r0-eth0": {
+ "helloRx": 0,
+ "helloTx": 1,
+ "joinRx": 0,
+ "joinTx": 0
+ }
+ }
+ }
+
+ result = get_pim_interface_traffic(tgen, input_dict)
+
+ Returns
+ -------
+ errormsg(str) or True
+ """
+
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+ output_dict = {}
+ for dut in input_dict.keys():
+ if dut not in tgen.routers():
+ continue
+
+ rnode = tgen.routers()[dut]
+
+ logger.info("[DUT: %s]: Verifying pim interface traffic", dut)
+
+ def show_pim_intf_traffic(rnode, dut, input_dict, output_dict):
+ show_pim_intf_traffic_json = run_frr_cmd(
+ rnode, "show ipv6 pim interface traffic json", isjson=True
+ )
+
+ output_dict[dut] = {}
+ for intf, data in input_dict[dut].items():
+ interface_json = show_pim_intf_traffic_json[intf]
+ for state in data:
+
+ # Verify Tx/Rx
+ if state in interface_json:
+ output_dict[dut][state] = interface_json[state]
+ else:
+ errormsg = (
+ "[DUT %s]: %s is not present"
+ "for interface %s [FAILED]!! " % (dut, state, intf)
+ )
+ return errormsg
+ return None
+
+ test_func = functools.partial(
+ show_pim_intf_traffic, rnode, dut, input_dict, output_dict
+ )
+ (result, out) = topotest.run_and_expect(test_func, None, count=20, wait=1)
+ if not result:
+ return out
+
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+ return output_dict
+
+
@retry(retry_timeout=40, diag_pct=0)
def verify_pim_interface(
- tgen, topo, dut, interface=None, interface_ip=None, expected=True
+ tgen, topo, dut, interface=None, interface_ip=None, addr_type="ipv4", expected=True
):
"""
Verify all PIM interface are up and running, config is verified
@@ -1803,29 +2055,48 @@ def verify_pim_interface(
logger.info("[DUT: %s]: Verifying PIM interface status:", dut)
rnode = tgen.routers()[dut]
- show_ip_pim_interface_json = rnode.vtysh_cmd(
- "show ip pim interface json", isjson=True
+
+ if addr_type == "ipv4":
+ addr_cmd = "ip"
+ pim_cmd = "pim"
+ elif addr_type == "ipv6":
+ addr_cmd = "ipv6"
+ pim_cmd = "pim6"
+ show_pim_interface_json = rnode.vtysh_cmd(
+ "show {} pim interface json".format(addr_cmd), isjson=True
)
- logger.info("show_ip_pim_interface_json: \n %s", show_ip_pim_interface_json)
+ logger.info("show_pim_interface_json: \n %s", show_pim_interface_json)
if interface_ip:
- if interface in show_ip_pim_interface_json:
- pim_intf_json = show_ip_pim_interface_json[interface]
+ if interface in show_pim_interface_json:
+ pim_intf_json = show_pim_interface_json[interface]
if pim_intf_json["address"] != interface_ip:
errormsg = (
- "[DUT %s]: PIM interface "
- "ip is not correct "
+ "[DUT %s]: %s interface "
+ "%s is not correct "
"[FAILED]!! Expected : %s, Found : %s"
- % (dut, pim_intf_json["address"], interface_ip)
+ % (
+ dut,
+ pim_cmd,
+ addr_cmd,
+ pim_intf_json["address"],
+ interface_ip,
+ )
)
return errormsg
else:
logger.info(
- "[DUT %s]: PIM interface "
- "ip is correct "
+ "[DUT %s]: %s interface "
+ "%s is correct "
"[Passed]!! Expected : %s, Found : %s"
- % (dut, pim_intf_json["address"], interface_ip)
+ % (
+ dut,
+ pim_cmd,
+ addr_cmd,
+ pim_intf_json["address"],
+ interface_ip,
+ )
)
return True
else:
@@ -1833,17 +2104,17 @@ def verify_pim_interface(
if "type" in data and data["type"] == "loopback":
continue
- if "pim" in data and data["pim"] == "enable":
+ if pim_cmd in data and data[pim_cmd] == "enable":
pim_interface = data["interface"]
- pim_intf_ip = data["ipv4"].split("/")[0]
+ pim_intf_ip = data[addr_type].split("/")[0]
- if pim_interface in show_ip_pim_interface_json:
- pim_intf_json = show_ip_pim_interface_json[pim_interface]
+ if pim_interface in show_pim_interface_json:
+ pim_intf_json = show_pim_interface_json[pim_interface]
else:
errormsg = (
- "[DUT %s]: PIM interface: %s "
- "PIM interface ip: %s, not Found"
- % (dut, pim_interface, pim_intf_ip)
+ "[DUT %s]: %s interface: %s "
+ "PIM interface %s: %s, not Found"
+ % (dut, pim_cmd, pim_interface, addr_cmd, pim_intf_ip)
)
return errormsg
@@ -1853,12 +2124,14 @@ def verify_pim_interface(
and pim_intf_json["state"] != "up"
):
errormsg = (
- "[DUT %s]: PIM interface: %s "
- "PIM interface ip: %s, status check "
+ "[DUT %s]: %s interface: %s "
+ "PIM interface %s: %s, status check "
"[FAILED]!! Expected : %s, Found : %s"
% (
dut,
+ pim_cmd,
pim_interface,
+ addr_cmd,
pim_intf_ip,
pim_interface,
pim_intf_json["state"],
@@ -1867,11 +2140,13 @@ def verify_pim_interface(
return errormsg
logger.info(
- "[DUT %s]: PIM interface: %s, "
- "interface ip: %s, status: %s"
+ "[DUT %s]: %s interface: %s, "
+ "interface %s: %s, status: %s"
" [PASSED]!!",
dut,
+ pim_cmd,
pim_interface,
+ addr_cmd,
pim_intf_ip,
pim_intf_json["state"],
)
@@ -1882,8 +2157,8 @@ def verify_pim_interface(
def clear_pim_interface_traffic(tgen, topo):
"""
- Clear ip/ipv6 pim interface traffice by running
- "clear ip/ipv6 pim interface traffic" cli
+ Clear ip pim interface traffic by running
+ "clear ip pim interface traffic" cli
Parameters
----------
@@ -1914,6 +2189,74 @@ def clear_pim_interface_traffic(tgen, topo):
return True
+def clear_pim6_interface_traffic(tgen, topo):
+ """
+ Clear ipv6 pim interface traffic by running
+ "clear ipv6 pim interface traffic" cli
+
+ Parameters
+ ----------
+ * `tgen`: topogen object
+ Usage
+ -----
+
+ result = clear_pim6_interface_traffic(tgen, topo)
+
+ Returns
+ -------
+ errormsg(str) or True
+ """
+
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+ for dut in tgen.routers():
+ if "pim" not in topo["routers"][dut]:
+ continue
+
+ rnode = tgen.routers()[dut]
+
+ logger.info("[DUT: %s]: Clearing pim6 interface traffic", dut)
+ result = run_frr_cmd(rnode, "clear ipv6 pim interface traffic")
+
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+
+ return True
+
+
+def clear_pim6_interfaces(tgen, topo):
+ """
+ Clear ipv6 pim interface by running
+ "clear ipv6 pim interface" cli
+
+ Parameters
+ ----------
+ * `tgen`: topogen object
+ Usage
+ -----
+
+ result = clear_pim6_interfaces(tgen, topo)
+
+ Returns
+ -------
+ errormsg(str) or True
+ """
+
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+ for dut in tgen.routers():
+ if "pim" not in topo["routers"][dut]:
+ continue
+
+ rnode = tgen.routers()[dut]
+
+ logger.info("[DUT: %s]: Clearing pim6 interfaces", dut)
+ result = run_frr_cmd(rnode, "clear ipv6 pim interface")
+
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+
+ return True
+
+
def clear_pim_interfaces(tgen, dut):
"""
Clear ip/ipv6 pim interface by running
@@ -1961,8 +2304,8 @@ def clear_pim_interfaces(tgen, dut):
# Waiting for maximum 60 sec
fail_intf = []
for retry in range(1, 13):
- logger.info("[DUT: %s]: Waiting for 5 sec for PIM neighbors" " to come up", dut)
sleep(5)
+ logger.info("[DUT: %s]: Waiting for 5 sec for PIM neighbors" " to come up", dut)
run_json_after = run_frr_cmd(rnode, "show ip pim neighbor json", isjson=True)
found = True
for pim_intf in nh_before_clear.keys():
@@ -2212,6 +2555,35 @@ def clear_mroute(tgen, dut=None):
logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+def clear_pim6_mroute(tgen, dut=None):
+ """
+ Clear ipv6 mroute by running "clear ipv6 mroute" cli
+
+ Parameters
+ ----------
+ * `tgen`: topogen object
+ * `dut`: device under test, default None
+
+ Usage
+ -----
+ clear_mroute(tgen, dut)
+ """
+
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+ router_list = tgen.routers()
+ for router, rnode in router_list.items():
+ if dut is not None and router != dut:
+ continue
+
+ logger.debug("[DUT: %s]: Clearing ipv6 mroute", router)
+ rnode.vtysh_cmd("clear ipv6 mroute")
+
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+
+ return True
+
+
def reconfig_interfaces(tgen, topo, senderRouter, receiverRouter, packet=None):
"""
Configure interface ip for sender and receiver routers
@@ -2812,7 +3184,14 @@ def enable_disable_pim_bsm(tgen, router, intf, enable=True):
@retry(retry_timeout=60, diag_pct=0)
def verify_pim_join(
- tgen, topo, dut, interface, group_addresses, src_address=None, expected=True
+ tgen,
+ topo,
+ dut,
+ interface,
+ group_addresses,
+ src_address=None,
+ addr_type="ipv4",
+ expected=True,
):
"""
Verify ip/ipv6 pim join by running "show ip/ipv6 pim join" cli
@@ -2846,11 +3225,22 @@ def verify_pim_join(
rnode = tgen.routers()[dut]
logger.info("[DUT: %s]: Verifying pim join", dut)
- show_pim_join_json = run_frr_cmd(rnode, "show ip pim join json", isjson=True)
if type(group_addresses) is not list:
group_addresses = [group_addresses]
+ for grp in group_addresses:
+ addr_type = validate_ip_address(grp)
+
+ if addr_type == "ipv4":
+ ip_cmd = "ip"
+ elif addr_type == "ipv6":
+ ip_cmd = "ipv6"
+
+ show_pim_join_json = run_frr_cmd(
+ rnode, "show {} pim join json".format(ip_cmd), isjson=True
+ )
+
for grp_addr in group_addresses:
# Verify if IGMP is enabled in DUT
if "igmp" not in topo["routers"][dut]:
@@ -3660,7 +4050,7 @@ def verify_multicast_flag_state(
@retry(retry_timeout=40, diag_pct=0)
-def verify_igmp_interface(tgen, topo, dut, igmp_iface, interface_ip, expected=True):
+def verify_igmp_interface(tgen, dut, igmp_iface, interface_ip, expected=True):
"""
Verify all IGMP interface are up and running, config is verified
using "show ip igmp interface" cli
@@ -3884,7 +4274,7 @@ def verify_local_igmp_groups(tgen, dut, interface, group_addresses):
def verify_pim_interface_traffic(tgen, input_dict, return_stats=True, addr_type="ipv4"):
"""
- Verify ip pim interface traffice by running
+ Verify ip pim interface traffic by running
"show ip pim interface traffic" cli
Parameters
@@ -3950,6 +4340,661 @@ def verify_pim_interface_traffic(tgen, input_dict, return_stats=True, addr_type=
logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
return True if return_stats == False else output_dict
+
+@retry(retry_timeout=40, diag_pct=0)
+def verify_mld_groups(tgen, dut, interface, group_addresses, expected=True):
+ """
+ Verify IGMP groups are received from an intended interface
+ by running "show ip mld groups" command
+
+ Parameters
+ ----------
+ * `tgen`: topogen object
+ * `dut`: device under test
+ * `interface`: interface, from which MLD groups would be received
+ * `group_addresses`: MLD group address
+ * `expected` : expected results from API, by-default True
+
+ Usage
+ -----
+ dut = "r1"
+ interface = "r1-r0-eth0"
+ group_address = "ffaa::1"
+ result = verify_mld_groups(tgen, dut, interface, group_address)
+
+ Returns
+ -------
+ errormsg(str) or True
+ """
+
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+ if dut not in tgen.routers():
+ return False
+
+ rnode = tgen.routers()[dut]
+
+ logger.info("[DUT: %s]: Verifying mld groups received:", dut)
+ show_mld_json = run_frr_cmd(rnode, "show ipv6 mld groups json", isjson=True)
+
+ if type(group_addresses) is not list:
+ group_addresses = [group_addresses]
+
+ if interface in show_mld_json:
+ show_mld_json = show_mld_json[interface]["groups"]
+ else:
+ errormsg = (
+ "[DUT %s]: Verifying MLD group received"
+ " from interface %s [FAILED]!! " % (dut, interface)
+ )
+ return errormsg
+
+ found = False
+ for grp_addr in group_addresses:
+ for index in show_mld_json:
+ if index["group"] == grp_addr:
+ found = True
+ break
+ if found is not True:
+ errormsg = (
+ "[DUT %s]: Verifying MLD group received"
+ " from interface %s [FAILED]!! "
+ " Expected not found: %s" % (dut, interface, grp_addr)
+ )
+ return errormsg
+
+ logger.info(
+ "[DUT %s]: Verifying MLD group %s received "
+ "from interface %s [PASSED]!! ",
+ dut,
+ grp_addr,
+ interface,
+ )
+
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+ return True
+
+
+@retry(retry_timeout=40, diag_pct=0)
+def verify_mld_interface(tgen, dut, mld_iface, interface_ip, expected=True):
+ """
+ Verify all IGMP interface are up and running, config is verified
+ using "show ip mld interface" cli
+
+ Parameters
+ ----------
+ * `tgen`: topogen object
+ * `topo` : json file data
+ * `dut` : device under test
+ * `mld_iface` : interface name
+ * `interface_ip` : interface ip address
+ * `expected` : expected results from API, by-default True
+
+ Usage
+ -----
+ result = verify_mld_interface(tgen, topo, dut, mld_iface, interface_ip)
+
+ Returns
+ -------
+ errormsg(str) or True
+ """
+
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+ for router in tgen.routers():
+ if router != dut:
+ continue
+
+ logger.info("[DUT: %s]: Verifying MLD interface status:", dut)
+
+ rnode = tgen.routers()[dut]
+ show_mld_interface_json = run_frr_cmd(
+ rnode, "show ipv6 mld interface json", isjson=True
+ )
+
+ if mld_iface in show_mld_interface_json:
+ mld_intf_json = show_mld_interface_json[mld_iface]
+ # Verifying igmp interface
+ if mld_intf_json["address"] != interface_ip:
+ errormsg = (
+ "[DUT %s]: igmp interface ip is not correct "
+ "[FAILED]!! Expected : %s, Found : %s"
+ % (dut, mld_intf_json["address"], interface_ip)
+ )
+ return errormsg
+
+ logger.info(
+ "[DUT %s]: igmp interface: %s, " "interface ip: %s" " [PASSED]!!",
+ dut,
+ mld_iface,
+ interface_ip,
+ )
+ else:
+ errormsg = (
+ "[DUT %s]: igmp interface: %s "
+ "igmp interface ip: %s, is not present "
+ % (dut, mld_iface, interface_ip)
+ )
+ return errormsg
+
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+ return True
+
+
+@retry(retry_timeout=60, diag_pct=0)
+def verify_mld_config(tgen, input_dict, stats_return=False, expected=True):
+ """
+ Verify mld interface details, verifying following configs:
+ timerQueryInterval
+ timerQueryResponseIntervalMsec
+ lastMemberQueryCount
+ timerLastMemberQueryMsec
+
+ Parameters
+ ----------
+ * `tgen`: topogen object
+ * `input_dict` : Input dict data, required to verify
+ timer
+ * `stats_return`: If user wants API to return statistics
+ * `expected` : expected results from API, by-default True
+
+ Usage
+ -----
+ input_dict ={
+ "l1": {
+ "mld": {
+ "interfaces": {
+ "l1-i1-eth1": {
+ "mld": {
+ "query": {
+ "query-interval" : 200,
+ "query-max-response-time" : 100
+ },
+ "statistics": {
+ "queryV2" : 2,
+ "reportV2" : 1
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ result = verify_mld_config(tgen, input_dict, stats_return)
+
+ Returns
+ -------
+ errormsg(str) or True
+ """
+
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+ for dut in input_dict.keys():
+ rnode = tgen.routers()[dut]
+
+ for interface, data in input_dict[dut]["igmp"]["interfaces"].items():
+
+ statistics = False
+ report = False
+ if "statistics" in input_dict[dut]["igmp"]["interfaces"][interface]["igmp"]:
+ statistics = True
+ cmd = "show ipv6 mld statistics"
+ else:
+ cmd = "show ipv6 mld"
+
+ logger.info("[DUT: %s]: Verifying MLD interface %s detail:", dut, interface)
+
+ if statistics:
+ if (
+ "report"
+ in input_dict[dut]["mld"]["interfaces"][interface]["mld"][
+ "statistics"
+ ]
+ ):
+ report = True
+
+ if statistics and report:
+ show_ipv6_mld_intf_json = run_frr_cmd(
+ rnode, "{} json".format(cmd), isjson=True
+ )
+ intf_detail_json = show_ipv6_mld_intf_json["global"]
+ else:
+ show_ipv6_mld_intf_json = run_frr_cmd(
+ rnode, "{} interface {} json".format(cmd, interface), isjson=True
+ )
+
+ if not report:
+ if interface not in show_ipv6_mld_intf_json:
+ errormsg = (
+ "[DUT %s]: MLD interface: %s "
+ " is not present in CLI output "
+ "[FAILED]!! " % (dut, interface)
+ )
+ return errormsg
+
+ else:
+ intf_detail_json = show_ipv6_mld_intf_json[interface]
+
+ if stats_return:
+ mld_stats = {}
+
+ if "statistics" in data["mld"]:
+ if stats_return:
+ mld_stats["statistics"] = {}
+ for query, value in data["mld"]["statistics"].items():
+ if query == "queryV1":
+ # Verifying IGMP interface queryV2 statistics
+ if stats_return:
+ mld_stats["statistics"][query] = intf_detail_json["queryV1"]
+
+ else:
+ if intf_detail_json["queryV1"] != value:
+ errormsg = (
+ "[DUT %s]: MLD interface: %s "
+ " queryV1 statistics verification "
+ "[FAILED]!! Expected : %s,"
+ " Found : %s"
+ % (
+ dut,
+ interface,
+ value,
+ intf_detail_json["queryV1"],
+ )
+ )
+ return errormsg
+
+ logger.info(
+ "[DUT %s]: MLD interface: %s "
+ "queryV1 statistics is %s",
+ dut,
+ interface,
+ value,
+ )
+
+ if query == "reportV1":
+ # Verifying IGMP interface timerV2 statistics
+ if stats_return:
+ mld_stats["statistics"][query] = intf_detail_json[
+ "reportV1"
+ ]
+
+ else:
+ if intf_detail_json["reportV1"] <= value:
+ errormsg = (
+ "[DUT %s]: MLD reportV1 "
+ "statistics verification "
+ "[FAILED]!! Expected : %s "
+ "or more, Found : %s"
+ % (
+ dut,
+ interface,
+ value,
+ )
+ )
+ return errormsg
+
+ logger.info(
+ "[DUT %s]: MLD reportV1 " "statistics is %s",
+ dut,
+ intf_detail_json["reportV1"],
+ )
+
+ if "query" in data["mld"]:
+ for query, value in data["mld"]["query"].items():
+ if query == "query-interval":
+ # Verifying IGMP interface query interval timer
+ if intf_detail_json["timerQueryInterval"] != value:
+ errormsg = (
+ "[DUT %s]: MLD interface: %s "
+ " query-interval verification "
+ "[FAILED]!! Expected : %s,"
+ " Found : %s"
+ % (
+ dut,
+ interface,
+ value,
+ intf_detail_json["timerQueryInterval"],
+ )
+ )
+ return errormsg
+
+ logger.info(
+ "[DUT %s]: MLD interface: %s " "query-interval is %s",
+ dut,
+ interface,
+ value,
+ )
+
+ if query == "query-max-response-time":
+ # Verifying IGMP interface query max response timer
+ if (
+ intf_detail_json["timerQueryResponseIntervalMsec"]
+ != value * 100
+ ):
+ errormsg = (
+ "[DUT %s]: MLD interface: %s "
+ "query-max-response-time "
+ "verification [FAILED]!!"
+ " Expected : %s, Found : %s"
+ % (
+ dut,
+ interface,
+ value * 1000,
+ intf_detail_json["timerQueryResponseIntervalMsec"],
+ )
+ )
+ return errormsg
+
+ logger.info(
+ "[DUT %s]: MLD interface: %s "
+ "query-max-response-time is %s ms",
+ dut,
+ interface,
+ value * 100,
+ )
+
+ if query == "last-member-query-count":
+ # Verifying IGMP interface last member query count
+ if intf_detail_json["lastMemberQueryCount"] != value:
+ errormsg = (
+ "[DUT %s]: MLD interface: %s "
+ "last-member-query-count "
+ "verification [FAILED]!!"
+ " Expected : %s, Found : %s"
+ % (
+ dut,
+ interface,
+ value,
+ intf_detail_json["lastMemberQueryCount"],
+ )
+ )
+ return errormsg
+
+ logger.info(
+ "[DUT %s]: MLD interface: %s "
+ "last-member-query-count is %s ms",
+ dut,
+ interface,
+ value * 1000,
+ )
+
+ if query == "last-member-query-interval":
+ # Verifying IGMP interface last member query interval
+ if (
+ intf_detail_json["timerLastMemberQueryMsec"]
+ != value * 100 * intf_detail_json["lastMemberQueryCount"]
+ ):
+ errormsg = (
+ "[DUT %s]: MLD interface: %s "
+ "last-member-query-interval "
+ "verification [FAILED]!!"
+ " Expected : %s, Found : %s"
+ % (
+ dut,
+ interface,
+ value * 1000,
+ intf_detail_json["timerLastMemberQueryMsec"],
+ )
+ )
+ return errormsg
+
+ logger.info(
+ "[DUT %s]: MLD interface: %s "
+ "last-member-query-interval is %s ms",
+ dut,
+ interface,
+ value * intf_detail_json["lastMemberQueryCount"] * 100,
+ )
+
+ if "version" in data["mld"]:
+ # Verifying IGMP interface state is up
+ if intf_detail_json["state"] != "up":
+ errormsg = (
+ "[DUT %s]: MLD interface: %s "
+ " state: %s verification "
+ "[FAILED]!!" % (dut, interface, intf_detail_json["state"])
+ )
+ return errormsg
+
+ logger.info(
+ "[DUT %s]: MLD interface: %s " "state: %s",
+ dut,
+ interface,
+ intf_detail_json["state"],
+ )
+
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+ return True if stats_return == False else mld_stats
+
+
+@retry(retry_timeout=60, diag_pct=0)
+def verify_pim_nexthop(tgen, topo, dut, nexthop, addr_type):
+ """
+ Verify all PIM nexthop details using "show ip/ipv6 pim neighbor" cli
+
+ Parameters
+ ----------
+ * `tgen`: topogen object
+ * `topo` : json file data
+ * `dut` : dut info
+ * `nexthop` : nexthop ip/ipv6 address
+
+ Usage
+ -----
+ result = verify_pim_nexthop(tgen, topo, dut, nexthop)
+
+ Returns
+ -------
+ errormsg(str) or True
+ """
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+ rnode = tgen.routers()[dut]
+
+ if addr_type == "ipv4":
+ ip_cmd = "ip"
+ elif addr_type == "ipv6":
+ ip_cmd = "ipv6"
+
+ cmd = "show {} pim nexthop".format(addr_type)
+ pim_nexthop = rnode.vtysh_cmd(cmd)
+
+ if nexthop in pim_nexthop:
+ logger.info("[DUT %s]: Expected nexthop: %s, Found", dut, nexthop)
+ return True
+ else:
+ errormsg = "[DUT %s]: Nexthop not found: %s" % (dut, nexthop)
+ return errormsg
+
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+ return True
+
+
+@retry(retry_timeout=60, diag_pct=0)
+def verify_mroute_summary(
+ tgen, dut, sg_mroute=None, starg_mroute=None, total_mroute=None, addr_type="ipv4"
+):
+ """
+ Verify ip mroute summary has correct (*,g) (s,G) and total mroutes
+ by running "show ip mroutes summary json" cli
+
+ Parameters
+ ----------
+ * `tgen`: topogen object
+ * `dut`: device under test
+ * `sg_mroute`: Number of installed (s,g) mroute
+ * `starg_mroute`: Number installed of (*,g) mroute
+ * `Total_mroute`: Total number of installed mroutes
+ * 'addr_type : IPv4 or IPv6 address
+ * `return_json`: Whether to return raw json data
+
+ Usage
+ -----
+ dut = "r1"
+ sg_mroute = "4000"
+ starg_mroute= "2000"
+ total_mroute = "6000"
+ addr_type=IPv4 or IPv6
+ result = verify_mroute_summary(tgen, dut, sg_mroute=None, starg_mroute=None,
+ total_mroute= None)
+ Returns
+ -------
+ errormsg or True
+ """
+
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+ if dut not in tgen.routers():
+ return False
+
+ rnode = tgen.routers()[dut]
+
+ logger.info("[DUT: %s]: Verifying mroute summary", dut)
+
+ if addr_type == "ipv4":
+ ip_cmd = "ip"
+ elif addr_type == "ipv6":
+ ip_cmd = "ipv6"
+
+ cmd = "show {} mroute summary json".format(ip_cmd)
+ show_mroute_summary_json = run_frr_cmd(rnode, cmd, isjson=True)
+
+ if starg_mroute is not None:
+ if show_mroute_summary_json["wildcardGroup"]["installed"] != starg_mroute:
+ logger.error(
+ "Number of installed starg are: %s but expected: %s",
+ show_mroute_summary_json["wildcardGroup"]["installed"],
+ starg_mroute,
+ )
+ return False
+ logger.info(
+ "Number of installed starg routes are %s",
+ show_mroute_summary_json["wildcardGroup"]["installed"],
+ )
+
+ if sg_mroute is not None:
+ if show_mroute_summary_json["sourceGroup"]["installed"] != sg_mroute:
+ logger.error(
+ "Number of installed SG routes are: %s but expected: %s",
+ show_mroute_summary_json["sourceGroup"]["installed"],
+ sg_mroute,
+ )
+ return False
+ logger.info(
+ "Number of installed SG routes are %s",
+ show_mroute_summary_json["sourceGroup"]["installed"],
+ )
+
+ if total_mroute is not None:
+ if show_mroute_summary_json["totalNumOfInstalledMroutes"] != total_mroute:
+ logger.error(
+ "Total number of installed mroutes are: %s but expected: %s",
+ show_mroute_summary_json["totalNumOfInstalledMroutes"],
+ total_mroute,
+ )
+ return False
+ logger.info(
+ "Number of installed Total mroute are %s",
+ show_mroute_summary_json["totalNumOfInstalledMroutes"],
+ )
+
+ logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
+ return True
+
+
+def verify_sg_traffic(tgen, dut, groups, src, addr_type="ipv4"):
+ """
+ Verify multicast traffic by running
+ "show ip mroute count json" cli
+
+ Parameters
+ ----------
+ * `tgen`: topogen object
+ * `groups`: igmp or mld groups where traffic needs to be verified
+
+ Usage
+ -----
+ result = verify_sg_traffic(tgen, "r1", igmp_groups, srcaddress)
+
+ Returns
+ -------
+ errormsg(str) or True
+ """
+
+ logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+ result = False
+
+ rnode = tgen.routers()[dut]
+
+ logger.info("[DUT: %s]: Verifying multicast " "SG traffic", dut)
+
+ if addr_type == "ipv4":
+ cmd = "show ip mroute count json"
+ elif addr_type == "ipv6":
+ cmd = "show ipv6 mroute count json"
+ # import pdb; pdb.set_trace()
+ show_mroute_sg_traffic_json = run_frr_cmd(rnode, cmd, isjson=True)
+
+ if bool(show_mroute_sg_traffic_json) is False:
+ errormsg = "[DUT %s]: Json output is empty" % (dut)
+ return errormsg
+
+ before_traffic = {}
+ after_traffic = {}
+
+ for grp in groups:
+ if grp not in show_mroute_sg_traffic_json:
+ errormsg = "[DUT %s]: Verifying (%s, %s) mroute," "[FAILED]!! " % (
+ dut,
+ src,
+ grp,
+ )
+ if src not in show_mroute_sg_traffic_json[grp]:
+ errormsg = (
+ "[DUT %s]: Verifying source is not present in "
+ " %s [FAILED]!! " % (dut, src)
+ )
+ return errormsg
+
+ before_traffic[grp] = show_mroute_sg_traffic_json[grp][src]["packets"]
+
+ logger.info("Waiting for 10sec traffic to increament")
+ sleep(10)
+
+ show_mroute_sg_traffic_json = run_frr_cmd(rnode, cmd, isjson=True)
+
+ for grp in groups:
+ if grp not in show_mroute_sg_traffic_json:
+ errormsg = "[DUT %s]: Verifying (%s, %s) mroute," "[FAILED]!! " % (
+ dut,
+ src,
+ grp,
+ )
+ if src not in show_mroute_sg_traffic_json[grp]:
+ errormsg = (
+ "[DUT %s]: Verifying source is not present in "
+ " %s [FAILED]!! " % (dut, src)
+ )
+ return errormsg
+
+ after_traffic[grp] = show_mroute_sg_traffic_json[grp][src]["packets"]
+
+ for grp in groups:
+ if after_traffic[grp] < before_traffic[grp]:
+ errormsg = (
+ "[DUT %s]: Verifying igmp group %s source %s not increamenting traffic"
+ " [FAILED]!! " % (dut, grp, src)
+ )
+ return errormsg
+ else:
+ logger.info(
+ "[DUT %s]:igmp group %s source %s receiving traffic"
+ " [PASSED]!! " % (dut, grp, src)
+ )
+ result = True
+
+ return result
+
# def cleanup(self):
# super(McastTesterHelper, self).cleanup()
diff --git a/tests/topotests/multicast_pim6_static_rp_topo1/__init__.py b/tests/topotests/multicast_pim6_static_rp_topo1/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/multicast_pim6_static_rp_topo1/__init__.py
diff --git a/tests/topotests/multicast_pim_static_rp_topo1/multicast_pimv6_static_rp.json b/tests/topotests/multicast_pim6_static_rp_topo1/multicast_pim6_static_rp.json
index 9edfae4a2..9edfae4a2 100644
--- a/tests/topotests/multicast_pim_static_rp_topo1/multicast_pimv6_static_rp.json
+++ b/tests/topotests/multicast_pim6_static_rp_topo1/multicast_pim6_static_rp.json
diff --git a/tests/topotests/multicast_pim6_static_rp_topo1/test_multicast_pim6_static_rp1.py b/tests/topotests/multicast_pim6_static_rp_topo1/test_multicast_pim6_static_rp1.py
new file mode 100755
index 000000000..dd8818e92
--- /dev/null
+++ b/tests/topotests/multicast_pim6_static_rp_topo1/test_multicast_pim6_static_rp1.py
@@ -0,0 +1,1321 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2022 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 Multicast basic functionality:
+
+Topology:
+
+ _______r2_____
+ | |
+ iperf | | iperf
+ r0-----r1-------------r3-----r5
+ | |
+ |_____________|
+ r4
+
+Test steps
+- Create topology (setup module)
+- Bring up topology
+
+1. Verify upstream interfaces(IIF) and join state are updated
+ properly after adding and deleting the static RP
+2. Verify IIF and OIL in "show ipv6 PIM6 state" updated properly when
+ RP becomes unreachable
+3. Verify RP becomes reachable after MLD join received, PIM6 join
+ towards RP is sent immediately
+4. Verify (*,G) and (S,G) populated correctly when SPT and RPT
+ share the same path
+5. Verify OIF and RPF for (*,G) and (S,G) when static RP configure
+ in LHR router
+6. Verify OIF and RFP for (*,G) and (S,G) when static RP configure
+ in FHR router
+7. Verify (*,G) and (S,G) populated correctly when RPT and SPT path
+ are different
+8. Verify PIM6 join send towards the higher preferred RP
+9. Verify PIM6 prune send towards the lower preferred RP
+"""
+
+import os
+import sys
+import json
+import time
+import pytest
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+
+# Required to instantiate the topology builder class.
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib.topogen import Topogen, get_topogen
+
+from lib.common_config import (
+ start_topology,
+ write_test_header,
+ write_test_footer,
+ reset_config_on_routers,
+ step,
+ shutdown_bringup_interface,
+ kill_router_daemons,
+ start_router_daemons,
+ create_static_routes,
+ check_router_status,
+ socat_send_mld_join,
+ socat_send_pim6_traffic,
+ kill_socat,
+ topo_daemons,
+)
+from lib.pim import (
+ create_pim_config,
+ verify_upstream_iif,
+ verify_join_state_and_timer,
+ verify_mroutes,
+ verify_pim_neighbors,
+ verify_pim_interface_traffic,
+ verify_pim_rp_info,
+ verify_pim_state,
+ clear_pim6_interface_traffic,
+ clear_pim6_mroute,
+ verify_pim6_neighbors,
+ get_pim6_interface_traffic,
+ clear_pim6_interfaces,
+ verify_mld_groups,
+)
+from lib.topolog import logger
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+# Global variables
+GROUP_RANGE_1 = "ff08::/64"
+GROUP_ADDRESS_1 = "ff08::1"
+GROUP_RANGE_3 = "ffaa::/64"
+GROUP_ADDRESS_3 = "ffaa::1"
+GROUP_RANGE_4 = "ff00::/8"
+GROUP_ADDRESS_4 = "ff00::1"
+STAR = "*"
+SOURCE = "Static"
+ASSERT_MSG = "Testcase {} : Failed Error: {}"
+
+pytestmark = [pytest.mark.pim6d]
+
+
+def build_topo(tgen):
+ """Build function"""
+
+ # 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: %s", testsuite_run_time)
+ logger.info("=" * 40)
+
+ topology = """
+
+ _______r2_____
+ | |
+ iperf | | iperf
+ r0-----r1-------------r3-----r5
+ | |
+ |_____________|
+ r4
+
+ """
+ logger.info("Master Topology: \n %s", topology)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ json_file = "{}/multicast_pim6_static_rp.json".format(CWD)
+ tgen = Topogen(json_file, mod.__name__)
+ global TOPO
+ TOPO = tgen.json_topo
+
+ # ... and here it calls Mininet initialization functions.
+
+ # get list of daemons needs to be started for this suite.
+ daemons = topo_daemons(tgen, TOPO)
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start daemons and then start routers
+ start_topology(tgen, daemons)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, TOPO)
+
+ # Verify PIM6 neighbors
+ result = verify_pim6_neighbors(tgen, TOPO)
+ assert result is True, "setup_module :Failed \n Error:" " {}".format(result)
+
+ 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: %s", time.asctime(time.localtime(time.time())))
+ logger.info("=" * 40)
+
+
+#####################################################
+#
+# Local API
+#
+#####################################################
+
+
+def verify_state_incremented(state_before, state_after):
+ """
+ API to compare interface traffic state incrementing
+
+ Parameters
+ ----------
+ * `state_before` : State dictionary for any particular instance
+ * `state_after` : State dictionary for any particular instance
+ """
+
+ for router, state_data in state_before.items():
+ for state, value in state_data.items():
+ if state_before[router][state] >= state_after[router][state]:
+ errormsg = (
+ "[DUT: %s]: state %s value has not"
+ " incremented, Initial value: %s, "
+ "Current value: %s [FAILED!!]"
+ % (
+ router,
+ state,
+ state_before[router][state],
+ state_after[router][state],
+ )
+ )
+ return errormsg
+
+ logger.info(
+ "[DUT: %s]: State %s value is "
+ "incremented, Initial value: %s, Current value: %s"
+ " [PASSED!!]",
+ router,
+ state,
+ state_before[router][state],
+ state_after[router][state],
+ )
+
+ return True
+
+
+#####################################################
+#
+# Testcases
+#
+#####################################################
+
+
+def test_pim6_add_delete_static_RP_p0(request):
+ """
+ Verify upstream interfaces(IIF) and join state are updated
+ properly after adding and deleting the static RP
+ Verify IIF and OIL in "show ipv6 PIM6 state" updated properly when
+ RP becomes unreachable
+ Verify RP becomes reachable after MLD join received, PIM6 join
+ towards RP is sent immediately
+
+ TOPOlogy used:
+ r0------r1-----r2
+ iperf DUT RP
+ """
+
+ 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():
+ check_router_status(tgen)
+
+ step("Creating configuration from JSON")
+ kill_socat(tgen)
+ clear_pim6_mroute(tgen)
+ clear_pim6_interface_traffic(tgen, TOPO)
+ reset_config_on_routers(tgen)
+
+ step("Shut link b/w R1 and R3 and R1 and R4 as per testcase topology")
+ intf_r1_r3 = TOPO["routers"]["r1"]["links"]["r3"]["interface"]
+ intf_r1_r4 = TOPO["routers"]["r1"]["links"]["r4"]["interface"]
+ for intf in [intf_r1_r3, intf_r1_r4]:
+ shutdown_bringup_interface(tgen, "r1", intf, ifaceaction=False)
+
+ step("Enable PIM6 between r1 and r2")
+ step("Enable MLD on r1 interface and send MLD " "join {} to r1".\
+ format(GROUP_RANGE_1))
+ step("Configure r2 loopback interface as RP")
+ input_dict = {
+ "r2": {
+ "pim6": {
+ "rp": [
+ {
+ "rp_addr": TOPO["routers"]["r2"]["links"]["lo"]["ipv6"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE_1,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, TOPO, input_dict)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("r1: Verify show ipv6 mld group without any MLD join")
+ dut = "r1"
+ intf_r1_r0 = TOPO["routers"]["r1"]["links"]["r0"]["interface"]
+ result = verify_mld_groups(tgen, dut, intf_r1_r0, GROUP_ADDRESS_1, expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r1: mld group present without any MLD join \n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ step("Verify show ipv6 PIM6 interface traffic without any mld join")
+ state_dict = {
+ "r1": {TOPO["routers"]["r1"]["links"]["r2"]["interface"]: ["pruneTx"]}
+ }
+
+ state_before = verify_pim_interface_traffic(tgen, state_dict, addr_type="ipv6")
+ assert isinstance(
+ state_before, dict
+ ), "Testcase{} : Failed \n state_before is not dictionary \n " "Error: {}".format(
+ tc_name, result
+ )
+
+ step("send mld join {} to R1".format(GROUP_ADDRESS_1))
+ intf = TOPO["routers"]["r0"]["links"]["r1"]["interface"]
+ intf_ip = TOPO["routers"]["r0"]["links"]["r1"]["ipv6"].split("/")[0]
+ result = socat_send_mld_join(
+ tgen, "r0", "UDP6-RECV", GROUP_ADDRESS_1, intf, intf_ip
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("r1: Verify MLD groups")
+ result = verify_mld_groups(tgen, dut, intf_r1_r0, GROUP_ADDRESS_1)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify RP info")
+ dut = "r1"
+ oif = TOPO["routers"]["r1"]["links"]["r2"]["interface"]
+ iif = TOPO["routers"]["r1"]["links"]["r0"]["interface"]
+ rp_address = TOPO["routers"]["r2"]["links"]["lo"]["ipv6"].split("/")[0]
+ result = verify_pim_rp_info(tgen, TOPO, dut, GROUP_RANGE_1, oif, rp_address, SOURCE)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify upstream IIF interface")
+ result = verify_upstream_iif(tgen, dut, oif, STAR, GROUP_ADDRESS_1)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify upstream join state and join timer")
+ result = verify_join_state_and_timer(tgen, dut, oif, STAR, GROUP_ADDRESS_1)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify PIM6 state")
+ result = verify_pim_state(tgen, dut, oif, iif, GROUP_ADDRESS_1)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify ip mroutes")
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS_1, oif, iif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Delete RP configuration")
+ input_dict = {
+ "r2": {
+ "pim6": {
+ "rp": [
+ {
+ "rp_addr": TOPO["routers"]["r2"]["links"]["lo"]["ipv6"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE_1,
+ "delete": True,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, TOPO, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("r1: Verify RP info")
+ result = verify_pim_rp_info(
+ tgen, TOPO, dut, GROUP_RANGE_1, oif, rp_address, SOURCE, expected=False
+ )
+ assert (
+ result is not True
+ ), "Testcase {} :Failed \n " "RP: {} info is still present \n Error: {}".format(
+ tc_name, rp_address, result
+ )
+
+ step("r1: Verify upstream IIF interface")
+ result = verify_upstream_iif(tgen, dut, oif, STAR, GROUP_ADDRESS_1, expected=False)
+ assert result is not True, (
+ "Testcase {} :Failed \n "
+ "Upstream ({}, {}) is still in join state \n Error: {}".format(
+ tc_name, STAR, GROUP_ADDRESS_1, result
+ )
+ )
+
+ step("r1: Verify upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, oif, STAR, GROUP_ADDRESS_1, expected=False
+ )
+ assert result is not True, (
+ "Testcase {} :Failed \n "
+ "Upstream ({}, {}) timer is still running \n Error: {}".format(
+ tc_name, STAR, GROUP_ADDRESS_1, result
+ )
+ )
+
+ step("r1: Verify PIM6 state")
+ result = verify_pim_state(tgen, dut, oif, iif, GROUP_ADDRESS_1, expected=False)
+ assert result is not True, (
+ "Testcase {} :Failed \n "
+ "PIM state for group: {} is still Active \n Error: {}".format(
+ tc_name, GROUP_ADDRESS_1, result
+ )
+ )
+
+ step("r1: Verify ip mroutes")
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS_1, oif, iif, expected=False)
+ assert result is not True, (
+ "Testcase {} :Failed \n "
+ "mroute ({}, {}) is still present \n Error: {}".format(
+ tc_name, STAR, GROUP_ADDRESS_1, result
+ )
+ )
+
+ step("r1: Verify show ipv6 PIM6 interface traffic without any MLD join")
+ state_after = verify_pim_interface_traffic(tgen, state_dict, addr_type="ipv6")
+ assert isinstance(
+ state_after, dict
+ ), "Testcase{} : Failed \n state_before is not dictionary \n " "Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_state_incremented(state_before, state_after)
+ assert result is True, "Testcase{} : Failed Error: {}".format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_pim6_SPT_RPT_path_same_p1(request):
+ """
+ Verify (*,G) and (S,G) populated correctly when SPT and RPT
+ share the same path
+
+ Topology used:
+ ________r2_____
+ | |
+ iperf | | iperf
+ r0-----r1 r3-----r5
+
+ r1 : LHR
+ r2 : RP
+ r3 : FHR
+ """
+
+ 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)
+
+ step("Creating configuration from JSON")
+ kill_socat(tgen)
+ clear_pim6_mroute(tgen)
+ clear_pim6_interface_traffic(tgen, TOPO)
+ reset_config_on_routers(tgen)
+
+ step("Shut link b/w R1->R3, R1->R4 and R3->R1, R3->R4 as per " "testcase topology")
+ intf_r1_r3 = TOPO["routers"]["r1"]["links"]["r3"]["interface"]
+ intf_r1_r4 = TOPO["routers"]["r1"]["links"]["r4"]["interface"]
+ intf_r3_r1 = TOPO["routers"]["r3"]["links"]["r1"]["interface"]
+ intf_r3_r4 = TOPO["routers"]["r3"]["links"]["r4"]["interface"]
+ for intf in [intf_r1_r3, intf_r1_r4]:
+ shutdown_bringup_interface(tgen, "r1", intf, ifaceaction=False)
+
+ for intf in [intf_r3_r1, intf_r3_r4]:
+ shutdown_bringup_interface(tgen, "r3", intf, ifaceaction=False)
+
+ step("Enable the PIM6 on all the interfaces of r1, r2, r3 and r4 routers")
+ step("Configure RP on r2 (loopback interface) for the group range {}".\
+ format(GROUP_ADDRESS_1))
+ input_dict = {
+ "r2": {
+ "pim6": {
+ "rp": [
+ {
+ "rp_addr": TOPO["routers"]["r2"]["links"]["lo"]["ipv6"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE_1,
+ }
+ ]
+ }
+ }
+ }
+ result = create_pim_config(tgen, TOPO, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("Enable MLD on r1 interface and send MLD join {} to R1".format(GROUP_ADDRESS_1))
+ intf = TOPO["routers"]["r0"]["links"]["r1"]["interface"]
+ intf_ip = TOPO["routers"]["r0"]["links"]["r1"]["ipv6"].split("/")[0]
+ result = socat_send_mld_join(
+ tgen, "r0", "UDP6-RECV", GROUP_ADDRESS_1, intf, intf_ip
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("r1: Verify MLD groups")
+ dut = "r1"
+ intf_r1_r0 = TOPO["routers"]["r1"]["links"]["r0"]["interface"]
+ result = verify_mld_groups(tgen, dut, intf_r1_r0, GROUP_ADDRESS_1)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("Send multicast traffic from R5")
+ intf = TOPO["routers"]["r5"]["links"]["r3"]["interface"]
+ SOURCE_ADDRESS = TOPO["routers"]["r5"]["links"]["r3"]["ipv6"].split("/")[0]
+ result = socat_send_pim6_traffic(tgen, "r5", "UDP6-SEND", GROUP_ADDRESS_1, intf)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("r2: Verify RP info")
+ dut = "r2"
+ oif = "lo"
+ rp_address = TOPO["routers"]["r2"]["links"]["lo"]["ipv6"].split("/")[0]
+ result = verify_pim_rp_info(tgen, TOPO, dut, GROUP_RANGE_1, oif, rp_address, SOURCE)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream IIF interface")
+ dut = "r1"
+ iif = TOPO["routers"]["r1"]["links"]["r2"]["interface"]
+ result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS_1)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS_1)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (*, G) ip mroutes")
+ oif = TOPO["routers"]["r1"]["links"]["r0"]["interface"]
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS_1, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream IIF interface")
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_1)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_1
+ )
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (S, G) ip mroutes")
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_1, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r2: Verify (*, G) upstream IIF interface")
+ dut = "r2"
+ iif = "lo"
+ result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS_1)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r2: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS_1)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r2: Verify (*, G) ip mroutes")
+ oif = TOPO["routers"]["r2"]["links"]["r1"]["interface"]
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS_1, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r2: Verify (S, G) upstream IIF interface")
+ iif = TOPO["routers"]["r2"]["links"]["r3"]["interface"]
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_1)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r2: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_1
+ )
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r2: Verify (S, G) ip mroutes")
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_1, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream IIF interface")
+ dut = "r3"
+ iif = TOPO["routers"]["r3"]["links"]["r5"]["interface"]
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_1)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_1, expected=False
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r3: (S, G) upstream join state is up and join timer is running\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ step("r3: Verify (S, G) ip mroutes")
+ oif = TOPO["routers"]["r3"]["links"]["r2"]["interface"]
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_1, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_pim6_RP_configured_as_LHR_p1(request):
+ """
+ Verify OIF and RPF for (*,G) and (S,G) when static RP configure
+ in LHR router
+
+ Topology used:
+ ________r2_____
+ | |
+ iperf | | iperf
+ r0-----r1-------------r3-----r5
+
+ r1 : LHR/RP
+ r3 : FHR
+ """
+
+ 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)
+
+ step("Creating configuration from JSON")
+ kill_socat(tgen)
+ clear_pim6_mroute(tgen)
+ clear_pim6_interface_traffic(tgen, TOPO)
+ reset_config_on_routers(tgen)
+
+ step("Enable MLD on r1 interface")
+ step("Enable the PIM6 on all the interfaces of r1, r2, r3 and r4 routers")
+
+ step("r1: Configure r1(LHR) as RP")
+ input_dict = {
+ "r1": {
+ "pim6": {
+ "rp": [
+ {
+ "rp_addr": TOPO["routers"]["r1"]["links"]["lo"]["ipv6"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE_1,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, TOPO, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("r1: Shut not Shut loopback interface")
+ shutdown_bringup_interface(tgen, "r1", "lo", False)
+ shutdown_bringup_interface(tgen, "r1", "lo", True)
+
+ step("r1: Verify RP info")
+ dut = "r1"
+ iif = "lo"
+ oif = TOPO["routers"]["r1"]["links"]["r0"]["interface"]
+ rp_address = TOPO["routers"]["r1"]["links"]["lo"]["ipv6"].split("/")[0]
+ result = verify_pim_rp_info(tgen, TOPO, dut, GROUP_RANGE_1, iif, rp_address, SOURCE)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("send mld join {} to R1".format(GROUP_ADDRESS_1))
+ intf = TOPO["routers"]["r0"]["links"]["r1"]["interface"]
+ intf_ip = TOPO["routers"]["r0"]["links"]["r1"]["ipv6"].split("/")[0]
+ result = socat_send_mld_join(
+ tgen, "r0", "UDP6-RECV", GROUP_ADDRESS_1, intf, intf_ip
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("r1: Verify MLD groups")
+ dut = "r1"
+ intf_r1_r0 = TOPO["routers"]["r1"]["links"]["r0"]["interface"]
+ result = verify_mld_groups(tgen, dut, intf_r1_r0, GROUP_ADDRESS_1)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r5: Send multicast traffic for group {}".format(GROUP_ADDRESS_1))
+ intf = TOPO["routers"]["r5"]["links"]["r3"]["interface"]
+ SOURCE_ADDRESS = TOPO["routers"]["r5"]["links"]["r3"]["ipv6"].split("/")[0]
+ result = socat_send_pim6_traffic(tgen, "r5", "UDP6-SEND", GROUP_ADDRESS_1, intf)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream IIF interface")
+ result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS_1)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS_1)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (*, G) ip mroutes")
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS_1, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream IIF interface")
+ iif = TOPO["routers"]["r1"]["links"]["r3"]["interface"]
+ SOURCE_ADDRESS = TOPO["routers"]["r5"]["links"]["r3"]["ipv6"].split("/")[0]
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_1)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_1
+ )
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (S, G) ip mroutes")
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_1, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream IIF interface")
+ dut = "r3"
+ iif = TOPO["routers"]["r3"]["links"]["r5"]["interface"]
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_1)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_1, expected=False
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r3: (S, G) upstream join state is joined and join"
+ " timer is running \n Error: {}".format(tc_name, result)
+ )
+
+ step("r3: Verify (S, G) ip mroutes")
+ oif = TOPO["routers"]["r3"]["links"]["r1"]["interface"]
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_1, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_pim6_RP_configured_as_FHR_p1(request):
+ """
+ Verify OIF and RFP for (*,G) and (S,G) when static RP configure
+ in FHR router
+
+ Topology used:
+ ________r2_____
+ | |
+ iperf | | iperf
+ r0-----r1-------------r3-----r5
+
+ r1 : LHR
+ r3 : FHR/RP
+ """
+
+ 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)
+
+ step("Creating configuration from JSON")
+ kill_socat(tgen)
+ clear_pim6_mroute(tgen)
+ clear_pim6_interface_traffic(tgen, TOPO)
+ reset_config_on_routers(tgen)
+
+ step("Enable MLD on r1 interface")
+ step("Enable the PIM6 on all the interfaces of r1, r2, r3 and r4 routers")
+ step("r3: Configure r3(FHR) as RP")
+ input_dict = {
+ "r3": {
+ "pim6": {
+ "rp": [
+ {
+ "rp_addr": TOPO["routers"]["r3"]["links"]["lo"]["ipv6"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE_1,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, TOPO, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("r1: Verify RP info")
+ dut = "r1"
+ iif = TOPO["routers"]["r1"]["links"]["r3"]["interface"]
+ oif = TOPO["routers"]["r1"]["links"]["r0"]["interface"]
+ rp_address = TOPO["routers"]["r3"]["links"]["lo"]["ipv6"].split("/")[0]
+ result = verify_pim_rp_info(tgen, TOPO, dut, GROUP_RANGE_1, iif, rp_address, SOURCE)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("send mld join {} to R1".format(GROUP_ADDRESS_1))
+ intf = TOPO["routers"]["r0"]["links"]["r1"]["interface"]
+ intf_ip = TOPO["routers"]["r0"]["links"]["r1"]["ipv6"].split("/")[0]
+ result = socat_send_mld_join(
+ tgen, "r0", "UDP6-RECV", GROUP_ADDRESS_1, intf, intf_ip
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("r1: Verify MLD groups")
+ dut = "r1"
+ intf_r1_r0 = TOPO["routers"]["r1"]["links"]["r0"]["interface"]
+ result = verify_mld_groups(tgen, dut, intf_r1_r0, GROUP_ADDRESS_1)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r5: Send multicast traffic for group {}".format(GROUP_ADDRESS_1))
+ intf = TOPO["routers"]["r5"]["links"]["r3"]["interface"]
+ SOURCE_ADDRESS = TOPO["routers"]["r5"]["links"]["r3"]["ipv6"].split("/")[0]
+ result = socat_send_pim6_traffic(tgen, "r5", "UDP6-SEND", GROUP_ADDRESS_1, intf)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream IIF interface")
+ result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS_1)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS_1)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (*, G) ip mroutes")
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS_1, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream IIF interface")
+ SOURCE_ADDRESS = TOPO["routers"]["r5"]["links"]["r3"]["ipv6"].split("/")[0]
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_1)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_1
+ )
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (S, G) ip mroutes")
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_1, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream IIF interface")
+ dut = "r3"
+ iif = TOPO["routers"]["r3"]["links"]["r5"]["interface"]
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_1)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_1, expected=False
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ step("r3: Verify (S, G) ip mroutes")
+ oif = TOPO["routers"]["r3"]["links"]["r1"]["interface"]
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_1, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_pim6_SPT_RPT_path_different_p1(request):
+ """
+ Verify (*,G) and (S,G) populated correctly when RPT and SPT path
+ are different
+
+ Topology used:
+ ________r2_____
+ | |
+ iperf | | iperf
+ r0-----r1-------------r3-----r5
+
+ r1: LHR
+ r2: RP
+ r3: FHR
+ """
+
+ 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)
+
+ step("Creating configuration from JSON")
+ kill_socat(tgen)
+ clear_pim6_mroute(tgen)
+ clear_pim6_interface_traffic(tgen, TOPO)
+ reset_config_on_routers(tgen)
+
+ step("Enable MLD on r1 interface")
+ step("Enable the PIM6 on all the interfaces of r1, r2, r3 and r4 routers")
+ step("r2: Configure r2 as RP")
+ input_dict = {
+ "r2": {
+ "pim6": {
+ "rp": [
+ {
+ "rp_addr": TOPO["routers"]["r2"]["links"]["lo"]["ipv6"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE_1,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, TOPO, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("r2: Verify RP info")
+ dut = "r2"
+ iif = "lo"
+ rp_address = TOPO["routers"]["r2"]["links"]["lo"]["ipv6"].split("/")[0]
+ result = verify_pim_rp_info(
+ tgen, TOPO, dut, GROUP_ADDRESS_1, iif, rp_address, SOURCE
+ )
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("send mld join {} to R1".format(GROUP_ADDRESS_1))
+ intf = TOPO["routers"]["r0"]["links"]["r1"]["interface"]
+ intf_ip = TOPO["routers"]["r0"]["links"]["r1"]["ipv6"].split("/")[0]
+ result = socat_send_mld_join(
+ tgen, "r0", "UDP6-RECV", GROUP_ADDRESS_1, intf, intf_ip
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("r1: Verify MLD groups")
+ dut = "r1"
+ intf_r1_r0 = TOPO["routers"]["r1"]["links"]["r0"]["interface"]
+ result = verify_mld_groups(tgen, dut, intf_r1_r0, GROUP_ADDRESS_1)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r5: Send multicast traffic for group {}".format(GROUP_ADDRESS_1))
+ intf = TOPO["routers"]["r5"]["links"]["r3"]["interface"]
+ SOURCE_ADDRESS = TOPO["routers"]["r5"]["links"]["r3"]["ipv6"].split("/")[0]
+ result = socat_send_pim6_traffic(tgen, "r5", "UDP6-SEND", GROUP_ADDRESS_1, intf)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream IIF interface")
+ dut = "r1"
+ iif = TOPO["routers"]["r1"]["links"]["r2"]["interface"]
+ oif = TOPO["routers"]["r1"]["links"]["r0"]["interface"]
+ result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS_1)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS_1)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (*, G) ip mroutes")
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS_1, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (S, G) ip mroutes")
+ iif = TOPO["routers"]["r1"]["links"]["r3"]["interface"]
+ SOURCE_ADDRESS = TOPO["routers"]["r5"]["links"]["r3"]["ipv6"].split("/")[0]
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_1, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream IIF interface")
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_1)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_1
+ )
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r2: Verify (*, G) upstream IIF interface")
+ dut = "r2"
+ iif = "lo"
+ result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS_1)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r2: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS_1)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r2: Verify (*, G) ip mroutes")
+ oif = TOPO["routers"]["r2"]["links"]["r1"]["interface"]
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS_1, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream IIF interface")
+ dut = "r3"
+ iif = TOPO["routers"]["r3"]["links"]["r5"]["interface"]
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_1)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_1, expected=False
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ step("r3: Verify (S, G) ip mroutes")
+ oif = TOPO["routers"]["r3"]["links"]["r1"]["interface"]
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_1, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r2: Verify (S, G) upstream IIF interface")
+ dut = "r2"
+ iif = TOPO["routers"]["r2"]["links"]["r3"]["interface"]
+ result = verify_upstream_iif(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_1, joinState="NotJoined"
+ )
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r2: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_1, expected=False
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r2: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ step("r2: Verify (S, G) ip mroutes")
+ oif = "none"
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_1, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_pim6_send_join_on_higher_preffered_rp_p1(request):
+ """
+ Verify PIM6 join send towards the higher preferred RP
+ Verify PIM6 prune send towards the lower preferred RP
+
+ Topology used:
+ _______r2
+ |
+ iperf |
+ r0-----r1
+ |
+ |_______r4
+ """
+
+ 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)
+
+ step("Creating configuration from JSON")
+ kill_socat(tgen)
+ clear_pim6_mroute(tgen)
+ clear_pim6_interface_traffic(tgen, TOPO)
+ reset_config_on_routers(tgen)
+
+ step("Enable MLD on r1 interface")
+ step("Enable the PIM66 on all the interfaces of r1, r2, r3 and r4 routers")
+ step("Configure RP on r2 (loopback interface) for the group range {}".\
+ format(GROUP_RANGE_4))
+ input_dict = {
+ "r2": {
+ "pim6": {
+ "rp": [
+ {
+ "rp_addr": TOPO["routers"]["r2"]["links"]["lo"]["ipv6"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE_4,
+ }
+ ]
+ }
+ }
+ }
+ result = create_pim_config(tgen, TOPO, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("r3 : Make all interface not reachable")
+ intf_r3_r1 = TOPO["routers"]["r3"]["links"]["r1"]["interface"]
+ intf_r3_r2 = TOPO["routers"]["r3"]["links"]["r2"]["interface"]
+ intf_r3_r4 = TOPO["routers"]["r3"]["links"]["r4"]["interface"]
+ intf_r1_r3 = TOPO["routers"]["r1"]["links"]["r3"]["interface"]
+ intf_r2_r3 = TOPO["routers"]["r2"]["links"]["r3"]["interface"]
+ intf_r4_r3 = TOPO["routers"]["r4"]["links"]["r3"]["interface"]
+
+ for dut, intf in zip(["r1", "r2", "r3"], [intf_r1_r3, intf_r2_r3, intf_r4_r3]):
+ shutdown_bringup_interface(tgen, dut, intf, ifaceaction=False)
+
+ for intf in [intf_r3_r1, intf_r3_r4, intf_r3_r4]:
+ shutdown_bringup_interface(tgen, "r3", intf, ifaceaction=False)
+
+ step("Verify show ipv6 PIM6 interface traffic without any mld join")
+ state_dict = {"r1": {TOPO["routers"]["r1"]["links"]["r4"]["interface"]: ["joinTx"]}}
+
+ state_before = get_pim6_interface_traffic(tgen, state_dict)
+ assert isinstance(
+ state_before, dict
+ ), "Testcase{} : Failed \n state_before is not dictionary \n " "Error: {}".format(
+ tc_name, result
+ )
+
+ step("r0: send mld join {} to R1".format(GROUP_ADDRESS_3))
+ intf = TOPO["routers"]["r0"]["links"]["r1"]["interface"]
+ intf_ip = TOPO["routers"]["r0"]["links"]["r1"]["ipv6"].split("/")[0]
+ result = socat_send_mld_join(
+ tgen, "r0", "UDP6-RECV", GROUP_ADDRESS_3, intf, intf_ip
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("r1: Verify MLD groups")
+ dut = "r1"
+ intf_r1_r0 = TOPO["routers"]["r1"]["links"]["r0"]["interface"]
+ result = verify_mld_groups(tgen, dut, intf_r1_r0, GROUP_ADDRESS_3)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("Configure RP on r4 (loopback interface) for the group range " "ffaa::/128")
+ input_dict = {
+ "r4": {
+ "pim6": {
+ "rp": [
+ {
+ "rp_addr": TOPO["routers"]["r4"]["links"]["lo"]["ipv6"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE_3,
+ }
+ ]
+ }
+ }
+ }
+ result = create_pim_config(tgen, TOPO, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("r1 : Verify RP info for group {}".format(GROUP_ADDRESS_4))
+ dut = "r1"
+ iif = TOPO["routers"]["r1"]["links"]["r2"]["interface"]
+ rp_address_1 = TOPO["routers"]["r2"]["links"]["lo"]["ipv6"].split("/")[0]
+ result = verify_pim_rp_info(
+ tgen, TOPO, dut, GROUP_ADDRESS_4, iif, rp_address_1, SOURCE
+ )
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1 : Verify RP info for group {}".format(GROUP_ADDRESS_3))
+ dut = "r1"
+ iif = TOPO["routers"]["r1"]["links"]["r4"]["interface"]
+ rp_address_2 = TOPO["routers"]["r4"]["links"]["lo"]["ipv6"].split("/")[0]
+ result = verify_pim_rp_info(
+ tgen, TOPO, dut, GROUP_ADDRESS_3, iif, rp_address_2, SOURCE
+ )
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1 : Verify join is sent to higher preferred RP")
+ step("r1 : Verify prune is sent to lower preferred RP")
+ state_after = get_pim6_interface_traffic(tgen, state_dict)
+ assert isinstance(
+ state_after, dict
+ ), "Testcase{} : Failed \n state_before is not dictionary \n " "Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_state_incremented(state_before, state_after)
+ assert result is True, "Testcase{} : Failed Error: {}".format(tc_name, result)
+
+ step("r1 : Verify ip mroutes")
+ oif = TOPO["routers"]["r1"]["links"]["r0"]["interface"]
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS_3, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1 : Verify PIM6 state")
+ result = verify_pim_state(tgen, dut, iif, oif, GROUP_ADDRESS_3)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1 : Verify upstream IIF interface")
+ result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS_3)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1 : Verify upstream join state and join timer")
+ result = verify_join_state_and_timer(tgen, dut, iif, STAR, GROUP_ADDRESS_3)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ clear_pim6_interface_traffic(tgen, TOPO)
+
+ step("r1 : Verify joinTx, pruneTx count before RP gets deleted")
+ state_dict = {
+ "r1": {
+ TOPO["routers"]["r1"]["links"]["r2"]["interface"]: ["joinTx"],
+ TOPO["routers"]["r1"]["links"]["r4"]["interface"]: ["pruneTx"],
+ }
+ }
+ state_before = get_pim6_interface_traffic(tgen, state_dict)
+ assert isinstance(
+ state_before, dict
+ ), "Testcase{} : Failed \n state_before is not dictionary \n " "Error: {}".format(
+ tc_name, result
+ )
+
+ step("r1 : Delete RP configuration for {}".format(GROUP_RANGE_3))
+ input_dict = {
+ "r4": {
+ "pim6": {
+ "rp": [
+ {
+ "rp_addr": TOPO["routers"]["r4"]["links"]["lo"]["ipv6"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE_3,
+ "delete": True,
+ }
+ ]
+ }
+ }
+ }
+ result = create_pim_config(tgen, TOPO, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("r1 : Verify rp-info for group {}".format(GROUP_RANGE_3))
+ iif = TOPO["routers"]["r1"]["links"]["r2"]["interface"]
+ result = verify_pim_rp_info(
+ tgen, TOPO, dut, GROUP_RANGE_3, iif, rp_address_1, SOURCE
+ )
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1 : Verify rp-info for group {}".format(GROUP_RANGE_4))
+ iif = TOPO["routers"]["r1"]["links"]["r4"]["interface"]
+ result = verify_pim_rp_info(
+ tgen, TOPO, dut, GROUP_RANGE_4, oif, rp_address_2, SOURCE, expected=False
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r1: rp-info is present for group {} \n Error: {}".format(tc_name,
+ GROUP_RANGE_4,
+ result)
+ )
+
+ step(
+ "r1 : Verify RPF interface updated in mroute when higher preferred"
+ "RP gets deleted"
+ )
+ iif = TOPO["routers"]["r1"]["links"]["r2"]["interface"]
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS_3, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+ logger.info("Expected behavior: %s", result)
+
+ step(
+ "r1 : Verify IIF and OIL in show ipv6 PIM6 state updated when higher"
+ "preferred overlapping RP is deleted"
+ )
+ result = verify_pim_state(tgen, dut, iif, oif, GROUP_ADDRESS_3)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step(
+ "r1 : Verify upstream IIF updated when higher preferred overlapping"
+ "RP deleted"
+ )
+ result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS_3)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step(
+ "r1 : Verify upstream join state and join timer updated when higher"
+ "preferred overlapping RP deleted"
+ )
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, STAR, GROUP_ADDRESS_3, addr_type="ipv6"
+ )
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step(
+ "r1 : Verify join is sent to lower preferred RP, when higher"
+ "preferred RP gets deleted"
+ )
+ step(
+ "r1 : Verify prune is sent to higher preferred RP when higher"
+ " preferred RP gets deleted"
+ )
+ state_after = get_pim6_interface_traffic(tgen, state_dict)
+ assert isinstance(
+ state_after, dict
+ ), "Testcase{} : Failed \n state_before is not dictionary \n " "Error: {}".format(
+ tc_name, result
+ )
+
+ result = verify_state_incremented(state_before, state_after)
+ assert result is True, "Testcase{} : Failed Error: {}".format(tc_name, result)
+ write_test_footer(tc_name)
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/multicast_pim6_static_rp_topo1/test_multicast_pim6_static_rp2.py b/tests/topotests/multicast_pim6_static_rp_topo1/test_multicast_pim6_static_rp2.py
new file mode 100755
index 000000000..f366708ec
--- /dev/null
+++ b/tests/topotests/multicast_pim6_static_rp_topo1/test_multicast_pim6_static_rp2.py
@@ -0,0 +1,1324 @@
+#!/usr/bin/env python
+
+#
+# Copyright (c) 2022 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 Multicast basic functionality:
+
+Topology:
+
+ _______r2_____
+ | |
+ iperf | | iperf
+ r0-----r1-------------r3-----r5
+ | |
+ |_____________|
+ r4
+
+Test steps
+- Create topology (setup module)
+- Bring up topology
+
+1. Configure multiple groups (10 grps) with same RP address
+2. Verify IIF and OIL in updated in mroute when upstream interface
+ configure as RP
+3. Verify RP info and (*,G) mroute after deleting the RP and shut /
+ no shut the RPF interface.
+"""
+
+import os
+import sys
+import json
+import time
+import pytest
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+sys.path.append(os.path.join(CWD, "../lib/"))
+
+# Required to instantiate the topology builder class.
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib.topogen import Topogen, get_topogen
+
+from lib.common_config import (
+ start_topology,
+ write_test_header,
+ write_test_footer,
+ reset_config_on_routers,
+ step,
+ shutdown_bringup_interface,
+ kill_router_daemons,
+ start_router_daemons,
+ create_static_routes,
+ check_router_status,
+ socat_send_mld_join,
+ socat_send_pim6_traffic,
+ kill_socat,
+ topo_daemons,
+)
+from lib.pim import (
+ create_pim_config,
+ verify_upstream_iif,
+ verify_join_state_and_timer,
+ verify_mroutes,
+ verify_pim_neighbors,
+ verify_pim_interface_traffic,
+ verify_pim_rp_info,
+ verify_pim_state,
+ clear_pim6_interface_traffic,
+ clear_pim6_mroute,
+ verify_pim6_neighbors,
+ get_pim6_interface_traffic,
+ clear_pim6_interfaces,
+ verify_mld_groups,
+)
+from lib.topolog import logger
+from lib.topojson import build_topo_from_json, build_config_from_json
+
+# Global variables
+GROUP_RANGE_1 = "ff08::/64"
+GROUP_ADDRESS_1 = "ff08::1"
+GROUP_RANGE_3 = "ffaa::/64"
+GROUP_ADDRESS_3 = "ffaa::1"
+GROUP_RANGE_LIST_1 = [
+ "ffaa::1/128",
+ "ffaa::2/128",
+ "ffaa::3/128",
+ "ffaa::4/128",
+ "ffaa::5/128",
+]
+GROUP_RANGE_LIST_2 = [
+ "ffaa::6/128",
+ "ffaa::7/128",
+ "ffaa::8/128",
+ "ffaa::9/128",
+ "ffaa::10/128",
+]
+GROUP_ADDRESS_LIST_1 = ["ffaa::1", "ffaa::2", "ffaa::3", "ffaa::4", "ffaa::5"]
+GROUP_ADDRESS_LIST_2 = ["ffaa::6", "ffaa::7", "ffaa::8", "ffaa::9", "ffaa::10"]
+STAR = "*"
+SOURCE = "Static"
+ASSERT_MSG = "Testcase {} : Failed Error: {}"
+
+pytestmark = [pytest.mark.pim6d]
+
+
+def build_topo(tgen):
+ """Build function"""
+
+ # 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: %s", testsuite_run_time)
+ logger.info("=" * 40)
+
+ topology = """
+
+ _______r2_____
+ | |
+ iperf | | iperf
+ r0-----r1-------------r3-----r5
+ | |
+ |_____________|
+ r4
+
+ """
+ logger.info("Master Topology: \n %s", topology)
+
+ logger.info("Running setup_module to create topology")
+
+ # This function initiates the topology build with Topogen...
+ json_file = "{}/multicast_pim6_static_rp.json".format(CWD)
+ tgen = Topogen(json_file, mod.__name__)
+ global TOPO
+ TOPO = tgen.json_topo
+
+ # ... and here it calls Mininet initialization functions.
+
+ # get list of daemons needs to be started for this suite.
+ daemons = topo_daemons(tgen, TOPO)
+
+ # Starting topology, create tmp files which are loaded to routers
+ # to start daemons and then start routers
+ start_topology(tgen, daemons)
+
+ # Don"t run this test if we have any failure.
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ # Creating configuration from JSON
+ build_config_from_json(tgen, TOPO)
+
+ # Verify PIM6 neighbors
+ result = verify_pim6_neighbors(tgen, TOPO)
+ assert result is True, "setup_module :Failed \n Error:" " {}".format(result)
+
+ 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: %s", time.asctime(time.localtime(time.time())))
+ logger.info("=" * 40)
+
+
+#####################################################
+#
+# Local API
+#
+#####################################################
+
+
+def verify_state_incremented(state_before, state_after):
+ """
+ API to compare interface traffic state incrementing
+
+ Parameters
+ ----------
+ * `state_before` : State dictionary for any particular instance
+ * `state_after` : State dictionary for any particular instance
+ """
+
+ for router, state_data in state_before.items():
+ for state, value in state_data.items():
+ if state_before[router][state] >= state_after[router][state]:
+ errormsg = (
+ "[DUT: %s]: state %s value has not"
+ " incremented, Initial value: %s, "
+ "Current value: %s [FAILED!!]"
+ % (
+ router,
+ state,
+ state_before[router][state],
+ state_after[router][state],
+ )
+ )
+ return errormsg
+
+ logger.info(
+ "[DUT: %s]: State %s value is "
+ "incremented, Initial value: %s, Current value: %s"
+ " [PASSED!!]",
+ router,
+ state,
+ state_before[router][state],
+ state_after[router][state],
+ )
+
+ return True
+
+
+#####################################################
+#
+# Testcases
+#
+#####################################################
+
+def test_pim6_multiple_groups_same_RP_address_p2(request):
+ """
+ Configure multiple groups (10 grps) with same RP address
+
+ Topology used:
+ ________r2_____
+ | |
+ iperf | | iperf
+ r0-----r1-------------r3-----r5
+
+ r1 : LHR
+ r2 : RP
+ r3 : FHR
+ """
+
+ 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)
+
+ step("Creating configuration from JSON")
+ kill_socat(tgen)
+ clear_pim6_mroute(tgen)
+ clear_pim6_interface_traffic(tgen, TOPO)
+ reset_config_on_routers(tgen)
+
+ step("Enable MLD on r1 interface")
+ step("Enable the PIM6 on all the interfaces of r1, r2, r3 and r4 routers")
+ step("r2: Configure r2 as RP")
+ input_dict = {
+ "r2": {
+ "pim6": {
+ "rp": [
+ {
+ "rp_addr": TOPO["routers"]["r2"]["links"]["lo"]["ipv6"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE_3,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, TOPO, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("r2: verify rp-info")
+ dut = "r2"
+ oif = "lo"
+ rp_address = TOPO["routers"]["r2"]["links"]["lo"]["ipv6"].split("/")[0]
+ result = verify_pim_rp_info(tgen, TOPO, dut, GROUP_RANGE_3, oif, rp_address, SOURCE)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ group_address_list = GROUP_ADDRESS_LIST_1 + GROUP_ADDRESS_LIST_2
+ step("r0: Send MLD join for 10 groups")
+ intf = TOPO["routers"]["r0"]["links"]["r1"]["interface"]
+ intf_ip = TOPO["routers"]["r0"]["links"]["r1"]["ipv6"].split("/")[0]
+ result = socat_send_mld_join(
+ tgen, "r0", "UDP6-RECV", group_address_list, intf, intf_ip
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("r1: Verify MLD groups")
+ dut = "r1"
+ intf_r1_r0 = TOPO["routers"]["r1"]["links"]["r0"]["interface"]
+ result = verify_mld_groups(tgen, dut, intf_r1_r0, group_address_list)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r5: Send multicast traffic for group {}".format(group_address_list))
+ intf = TOPO["routers"]["r5"]["links"]["r3"]["interface"]
+ SOURCE_ADDRESS = TOPO["routers"]["r5"]["links"]["r3"]["ipv6"].split("/")[0]
+ result = socat_send_pim6_traffic(tgen, "r5", "UDP6-SEND", group_address_list, intf)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream IIF interface")
+ dut = "r1"
+ iif = TOPO["routers"]["r1"]["links"]["r2"]["interface"]
+ result = verify_upstream_iif(tgen, dut, iif, STAR, group_address_list)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, STAR, group_address_list, addr_type="ipv6"
+ )
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (*, G) ip mroutes")
+ oif = TOPO["routers"]["r1"]["links"]["r0"]["interface"]
+ result = verify_mroutes(tgen, dut, STAR, group_address_list, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (S, G) ip mroutes")
+ iif = TOPO["routers"]["r1"]["links"]["r3"]["interface"]
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, group_address_list, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream IIF interface")
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, group_address_list)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, group_address_list, addr_type="ipv6"
+ )
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r2: Verify (*, G) upstream IIF interface")
+ dut = "r2"
+ iif = "lo"
+ result = verify_upstream_iif(tgen, dut, iif, STAR, group_address_list)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r2: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, STAR, group_address_list, addr_type="ipv6"
+ )
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r2: Verify (*, G) ip mroutes")
+ oif = TOPO["routers"]["r2"]["links"]["r1"]["interface"]
+ result = verify_mroutes(tgen, dut, STAR, group_address_list, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream IIF interface")
+ dut = "r3"
+ iif = TOPO["routers"]["r3"]["links"]["r5"]["interface"]
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, group_address_list)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen,
+ dut,
+ iif,
+ SOURCE_ADDRESS,
+ group_address_list,
+ addr_type="ipv6",
+ expected=False,
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ step("r3: Verify (S, G) ip mroutes")
+ oif = TOPO["routers"]["r3"]["links"]["r1"]["interface"]
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, group_address_list, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r2: Verify (S, G) upstream IIF interface")
+ dut = "r2"
+ iif = TOPO["routers"]["r2"]["links"]["r3"]["interface"]
+ result = verify_upstream_iif(
+ tgen, dut, iif, SOURCE_ADDRESS, group_address_list, joinState="NotJoined"
+ )
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r2: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen,
+ dut,
+ iif,
+ SOURCE_ADDRESS,
+ group_address_list,
+ addr_type="ipv6",
+ expected=False,
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r2: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ step("r2: Verify (S, G) ip mroutes")
+ oif = "none"
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, group_address_list, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Delete RP configuration")
+ input_dict = {
+ "r1": {
+ "pim6": {
+ "rp": [
+ {
+ "rp_addr": TOPO["routers"]["r2"]["links"]["lo"]["ipv6"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE_3,
+ "delete": True,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, TOPO, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("r1: Shut the interface r1-r2-eth1 from R1 to R2")
+ dut = "r1"
+ intf = TOPO["routers"]["r1"]["links"]["r2"]["interface"]
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ step("r1: No Shut the interface r1-r2-eth1 from R1 to R2")
+ shutdown_bringup_interface(tgen, dut, intf, True)
+
+ step("r1: Configure RP")
+ input_dict = {
+ "r1": {
+ "pim6": {
+ "rp": [
+ {
+ "rp_addr": TOPO["routers"]["r2"]["links"]["lo"]["ipv6"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE_3,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, TOPO, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("r1: Shut the interface r1-r0-eth0 from R1 to R2")
+ intf = TOPO["routers"]["r1"]["links"]["r0"]["interface"]
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ step("r1: No Shut the interface r1-r0-eth0 from R1 to R2")
+ shutdown_bringup_interface(tgen, dut, intf, True)
+
+ step("r1: Verify (*, G) upstream IIF interface")
+ dut = "r1"
+ iif = TOPO["routers"]["r1"]["links"]["r2"]["interface"]
+ result = verify_upstream_iif(tgen, dut, iif, STAR, group_address_list)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, STAR, group_address_list, addr_type="ipv6"
+ )
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (*, G) ip mroutes")
+ oif = TOPO["routers"]["r1"]["links"]["r0"]["interface"]
+ result = verify_mroutes(tgen, dut, STAR, group_address_list, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream IIF interface")
+ iif = TOPO["routers"]["r1"]["links"]["r3"]["interface"]
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, group_address_list)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, group_address_list, addr_type="ipv6"
+ )
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (S, G) ip mroutes")
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, group_address_list, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r2: Verify (*, G) upstream IIF interface")
+ dut = "r2"
+ iif = "lo"
+ result = verify_upstream_iif(tgen, dut, iif, STAR, group_address_list)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r2: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, STAR, group_address_list, addr_type="ipv6"
+ )
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r2: Verify (*, G) ip mroutes")
+ oif = TOPO["routers"]["r2"]["links"]["r1"]["interface"]
+ result = verify_mroutes(tgen, dut, STAR, group_address_list, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream IIF interface")
+ dut = "r3"
+ iif = TOPO["routers"]["r3"]["links"]["r5"]["interface"]
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, group_address_list)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen,
+ dut,
+ iif,
+ SOURCE_ADDRESS,
+ group_address_list,
+ addr_type="ipv6",
+ expected=False,
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ step("r3: Verify (S, G) ip mroutes")
+ oif = TOPO["routers"]["r3"]["links"]["r1"]["interface"]
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, group_address_list, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_pim6_multiple_groups_different_RP_address_p2(request):
+ """
+ Verify IIF and OIL in updated in mroute when upstream interface
+ configure as RP
+
+ Topology used:
+ ________r2_____
+ | |
+ iperf | | iperf
+ r0-----r1-------------r3-----r5
+ | |
+ |_____________|
+ r4
+ r1 : LHR
+ r2 & r4 : RP
+ r3 : FHR
+ """
+
+ 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)
+
+ step("Creating configuration from JSON")
+ kill_socat(tgen)
+ clear_pim6_mroute(tgen)
+ clear_pim6_interface_traffic(tgen, TOPO)
+ reset_config_on_routers(tgen)
+
+ step("Enable MLD on r1 interface")
+ step("Enable the PIM6 on all the interfaces of r1, r2, r3 and r4 routers")
+ step("r2: Configure r2 as RP")
+ step("r4: Configure r4 as RP")
+ input_dict = {
+ "r2": {
+ "pim6": {
+ "rp": [
+ {
+ "rp_addr": TOPO["routers"]["r2"]["links"]["lo"]["ipv6"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE_LIST_1,
+ }
+ ]
+ }
+ },
+ "r4": {
+ "pim6": {
+ "rp": [
+ {
+ "rp_addr": TOPO["routers"]["r4"]["links"]["lo"]["ipv6"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE_LIST_2,
+ }
+ ]
+ }
+ },
+ }
+
+ result = create_pim_config(tgen, TOPO, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("r2: Verify RP info")
+ dut = "r2"
+ oif = "lo"
+ rp_address = TOPO["routers"]["r2"]["links"]["lo"]["ipv6"].split("/")[0]
+ result = verify_pim_rp_info(
+ tgen, TOPO, dut, GROUP_RANGE_LIST_1, oif, rp_address, SOURCE
+ )
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r4: Verify RP info")
+ dut = "r4"
+ rp_address = TOPO["routers"]["r4"]["links"]["lo"]["ipv6"].split("/")[0]
+ result = verify_pim_rp_info(
+ tgen, TOPO, dut, GROUP_RANGE_LIST_2, oif, rp_address, SOURCE
+ )
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ group_address_list = GROUP_ADDRESS_LIST_1 + GROUP_ADDRESS_LIST_2
+ step("r0: Send MLD join for 10 groups")
+ intf = TOPO["routers"]["r0"]["links"]["r1"]["interface"]
+ intf_ip = TOPO["routers"]["r0"]["links"]["r1"]["ipv6"].split("/")[0]
+ result = socat_send_mld_join(
+ tgen, "r0", "UDP6-RECV", group_address_list, intf, intf_ip
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("r1: Verify MLD groups")
+ dut = "r1"
+ intf_r1_r0 = TOPO["routers"]["r1"]["links"]["r0"]["interface"]
+ result = verify_mld_groups(tgen, dut, intf_r1_r0, group_address_list)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r5: Send multicast traffic for group {}".format(group_address_list))
+ intf = TOPO["routers"]["r5"]["links"]["r3"]["interface"]
+ SOURCE_ADDRESS = TOPO["routers"]["r5"]["links"]["r3"]["ipv6"].split("/")[0]
+ result = socat_send_pim6_traffic(tgen, "r5", "UDP6-SEND", group_address_list, intf)
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream IIF interface")
+ dut = "r1"
+ iif = TOPO["routers"]["r1"]["links"]["r2"]["interface"]
+ result = verify_upstream_iif(tgen, dut, iif, STAR, group_address_list)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, STAR, group_address_list, addr_type="ipv6"
+ )
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (*, G) ip mroutes")
+ oif = TOPO["routers"]["r1"]["links"]["r0"]["interface"]
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS_LIST_1, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream IIF interface")
+ iif = TOPO["routers"]["r1"]["links"]["r3"]["interface"]
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, addr_type="ipv6"
+ )
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (S, G) ip mroutes")
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r2: Verify (*, G) upstream IIF interface")
+ dut = "r2"
+ iif = "lo"
+ result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_1)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r2: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_1, addr_type="ipv6"
+ )
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r2: Verify (*, G) ip mroutes")
+ oif = TOPO["routers"]["r2"]["links"]["r1"]["interface"]
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS_LIST_1, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r2: Verify (S, G) upstream IIF interface")
+ iif = TOPO["routers"]["r2"]["links"]["r3"]["interface"]
+ result = verify_upstream_iif(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, joinState="NotJoined"
+ )
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r2: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen,
+ dut,
+ iif,
+ SOURCE_ADDRESS,
+ GROUP_ADDRESS_LIST_1,
+ addr_type="ipv6",
+ expected=False,
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r2: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ step("r2: Verify (S, G) ip mroutes")
+ oif = "none"
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream IIF interface")
+ dut = "r3"
+ iif = TOPO["routers"]["r3"]["links"]["r5"]["interface"]
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen,
+ dut,
+ iif,
+ SOURCE_ADDRESS,
+ GROUP_ADDRESS_LIST_1,
+ addr_type="ipv6",
+ expected=False,
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ step("r3: Verify (S, G) ip mroutes")
+ oif = TOPO["routers"]["r3"]["links"]["r1"]["interface"]
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream IIF interface")
+ dut = "r1"
+ iif = TOPO["routers"]["r1"]["links"]["r4"]["interface"]
+ result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_2)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_2, addr_type="ipv6"
+ )
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (*, G) ip mroutes")
+ oif = TOPO["routers"]["r1"]["links"]["r0"]["interface"]
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS_LIST_2, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream IIF interface")
+ iif = TOPO["routers"]["r1"]["links"]["r3"]["interface"]
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, addr_type="ipv6"
+ )
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (S, G) ip mroutes")
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r4: Verify (*, G) upstream IIF interface")
+ dut = "r4"
+ iif = "lo"
+ result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_2)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r4: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_2, addr_type="ipv6"
+ )
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r4: Verify (*, G) ip mroutes")
+ oif = TOPO["routers"]["r4"]["links"]["r1"]["interface"]
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS_LIST_2, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r4: Verify (S, G) upstream IIF interface")
+ iif = TOPO["routers"]["r4"]["links"]["r3"]["interface"]
+ result = verify_upstream_iif(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, joinState="NotJoined"
+ )
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r4: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen,
+ dut,
+ iif,
+ SOURCE_ADDRESS,
+ GROUP_ADDRESS_LIST_2,
+ addr_type="ipv6",
+ expected=False,
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r4: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ step("r4: Verify (S, G) ip mroutes")
+ oif = "none"
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream IIF interface")
+ dut = "r3"
+ iif = TOPO["routers"]["r3"]["links"]["r5"]["interface"]
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen,
+ dut,
+ iif,
+ SOURCE_ADDRESS,
+ GROUP_ADDRESS_LIST_2,
+ addr_type="ipv6",
+ expected=False,
+ )
+ assert result is not True, "Testcase {} :Failed \n Error: {}".format(
+ tc_name, result
+ )
+
+ step("r3: Verify (S, G) ip mroutes")
+ oif = TOPO["routers"]["r3"]["links"]["r1"]["interface"]
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("Delete RP configuration")
+ input_dict = {
+ "r2": {
+ "pim6": {
+ "rp": [
+ {
+ "rp_addr": TOPO["routers"]["r2"]["links"]["lo"]["ipv6"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE_LIST_1,
+ "delete": True,
+ }
+ ]
+ }
+ },
+ "r4": {
+ "pim6": {
+ "rp": [
+ {
+ "rp_addr": TOPO["routers"]["r4"]["links"]["lo"]["ipv6"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE_LIST_2,
+ "delete": True,
+ }
+ ]
+ }
+ },
+ }
+
+ result = create_pim_config(tgen, TOPO, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("r1, r2, r3, r4: Re-configure RP")
+ input_dict = {
+ "r2": {
+ "pim6": {
+ "rp": [
+ {
+ "rp_addr": TOPO["routers"]["r2"]["links"]["lo"]["ipv6"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE_LIST_1,
+ }
+ ]
+ }
+ },
+ "r4": {
+ "pim6": {
+ "rp": [
+ {
+ "rp_addr": TOPO["routers"]["r4"]["links"]["lo"]["ipv6"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE_LIST_2,
+ }
+ ]
+ }
+ },
+ }
+
+ result = create_pim_config(tgen, TOPO, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("r1: Shut/No Shut the interfacesfrom R1 to R2, R4 and R0")
+ dut = "r1"
+ intf1 = TOPO["routers"]["r1"]["links"]["r2"]["interface"]
+ intf2 = TOPO["routers"]["r1"]["links"]["r4"]["interface"]
+ intf3 = TOPO["routers"]["r1"]["links"]["r0"]["interface"]
+ for intf in [intf1, intf2, intf3]:
+ shutdown_bringup_interface(tgen, dut, intf, False)
+ shutdown_bringup_interface(tgen, dut, intf, True)
+
+ step("r1: Verify (*, G) upstream IIF interface")
+ dut = "r1"
+ iif = TOPO["routers"]["r1"]["links"]["r2"]["interface"]
+ result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_1)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_1, addr_type="ipv6"
+ )
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (*, G) ip mroutes")
+ oif = TOPO["routers"]["r1"]["links"]["r0"]["interface"]
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS_LIST_1, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream IIF interface")
+ iif = TOPO["routers"]["r1"]["links"]["r3"]["interface"]
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, addr_type="ipv6"
+ )
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (S, G) ip mroutes")
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r2: Verify (*, G) upstream IIF interface")
+ dut = "r2"
+ iif = "lo"
+ result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_1)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r2: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_1, addr_type="ipv6"
+ )
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r2: Verify (*, G) ip mroutes")
+ oif = TOPO["routers"]["r2"]["links"]["r1"]["interface"]
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS_LIST_1, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r2: Verify (S, G) upstream IIF interface")
+ iif = TOPO["routers"]["r2"]["links"]["r3"]["interface"]
+ result = verify_upstream_iif(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, joinState="NotJoined"
+ )
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r2: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen,
+ dut,
+ iif,
+ SOURCE_ADDRESS,
+ GROUP_ADDRESS_LIST_1,
+ addr_type="ipv6",
+ expected=False,
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r2: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ step("r2: Verify (S, G) ip mroutes")
+ oif = "none"
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream IIF interface")
+ dut = "r3"
+ iif = TOPO["routers"]["r3"]["links"]["r5"]["interface"]
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen,
+ dut,
+ iif,
+ SOURCE_ADDRESS,
+ GROUP_ADDRESS_LIST_1,
+ addr_type="ipv6",
+ expected=False,
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ step("r3: Verify (S, G) ip mroutes")
+ oif = TOPO["routers"]["r3"]["links"]["r1"]["interface"]
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_1, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream IIF interface")
+ dut = "r1"
+ iif = TOPO["routers"]["r1"]["links"]["r4"]["interface"]
+ result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_2)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_2, addr_type="ipv6"
+ )
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (*, G) ip mroutes")
+ oif = TOPO["routers"]["r1"]["links"]["r0"]["interface"]
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS_LIST_2, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream IIF interface")
+ iif = TOPO["routers"]["r1"]["links"]["r3"]["interface"]
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, addr_type="ipv6"
+ )
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (S, G) ip mroutes")
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r4: Verify (*, G) upstream IIF interface")
+ dut = "r4"
+ iif = "lo"
+ result = verify_upstream_iif(tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_2)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r4: Verify (*, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen, dut, iif, STAR, GROUP_ADDRESS_LIST_2, addr_type="ipv6"
+ )
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r4: Verify (*, G) ip mroutes")
+ oif = TOPO["routers"]["r4"]["links"]["r1"]["interface"]
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS_LIST_2, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r4: Verify (S, G) upstream IIF interface")
+ iif = TOPO["routers"]["r4"]["links"]["r3"]["interface"]
+ result = verify_upstream_iif(
+ tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, joinState="NotJoined"
+ )
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r4: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen,
+ dut,
+ iif,
+ SOURCE_ADDRESS,
+ GROUP_ADDRESS_LIST_2,
+ addr_type="ipv6",
+ expected=False,
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r4: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ step("r4: Verify (S, G) ip mroutes")
+ oif = "none"
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream IIF interface")
+ dut = "r3"
+ iif = TOPO["routers"]["r3"]["links"]["r5"]["interface"]
+ result = verify_upstream_iif(tgen, dut, iif, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r3: Verify (S, G) upstream join state and join timer")
+ result = verify_join_state_and_timer(
+ tgen,
+ dut,
+ iif,
+ SOURCE_ADDRESS,
+ GROUP_ADDRESS_LIST_2,
+ addr_type="ipv6",
+ expected=False,
+ )
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r3: (S,G) upstream state is joined and join timer is running\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ step("r3: Verify (S, G) ip mroutes")
+ oif = TOPO["routers"]["r3"]["links"]["r1"]["interface"]
+ result = verify_mroutes(tgen, dut, SOURCE_ADDRESS, GROUP_ADDRESS_LIST_2, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ write_test_footer(tc_name)
+
+
+def test_pim6_delete_RP_shut_noshut_upstream_interface_p1(request):
+ """
+ Verify RP info and (*,G) mroute after deleting the RP and shut /
+ no shut the RPF interface.
+
+ Topology used:
+ ________r2_____
+ | |
+ iperf | |
+ r0-----r1-------------r3
+ """
+
+ 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)
+
+ step("Creating configuration from JSON")
+ kill_socat(tgen)
+ clear_pim6_mroute(tgen)
+ clear_pim6_interface_traffic(tgen, TOPO)
+ reset_config_on_routers(tgen)
+
+ step("Enable MLD on r1 interface")
+ step("Enable the PIM6 on all the interfaces of r1, r2, r3 and r4 routers")
+ step("r2: Configure r2 as RP")
+ input_dict = {
+ "r2": {
+ "pim6": {
+ "rp": [
+ {
+ "rp_addr": TOPO["routers"]["r2"]["links"]["lo"]["ipv6"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE_1,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, TOPO, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("r2: verify rp-info")
+ dut = "r2"
+ oif = "lo"
+ rp_address = TOPO["routers"]["r2"]["links"]["lo"]["ipv6"].split("/")[0]
+ result = verify_pim_rp_info(
+ tgen, TOPO, dut, GROUP_ADDRESS_1, oif, rp_address, SOURCE
+ )
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r0: Send MLD join")
+ intf = TOPO["routers"]["r0"]["links"]["r1"]["interface"]
+ intf_ip = TOPO["routers"]["r0"]["links"]["r1"]["ipv6"].split("/")[0]
+ result = socat_send_mld_join(
+ tgen, "r0", "UDP6-RECV", GROUP_ADDRESS_1, intf, intf_ip
+ )
+ assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
+
+ step("r1: Verify MLD groups")
+ dut = "r1"
+ intf_r1_r0 = TOPO["routers"]["r1"]["links"]["r0"]["interface"]
+ result = verify_mld_groups(tgen, dut, intf_r1_r0, GROUP_ADDRESS_1)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Verify (*, G) ip mroutes created")
+ iif = TOPO["routers"]["r1"]["links"]["r2"]["interface"]
+ oif = TOPO["routers"]["r1"]["links"]["r0"]["interface"]
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS_1, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r2: Verify (*, G) ip mroutes created")
+ dut = "r2"
+ iif = "lo"
+ oif = TOPO["routers"]["r2"]["links"]["r1"]["interface"]
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS_1, iif, oif)
+ assert result is True, ASSERT_MSG.format(tc_name, result)
+
+ step("r1: Delete RP configuration")
+ input_dict = {
+ "r1": {
+ "pim6": {
+ "rp": [
+ {
+ "rp_addr": TOPO["routers"]["r2"]["links"]["lo"]["ipv6"].split(
+ "/"
+ )[0],
+ "group_addr_range": GROUP_RANGE_1,
+ "delete": True,
+ }
+ ]
+ }
+ }
+ }
+
+ result = create_pim_config(tgen, TOPO, input_dict)
+ assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
+
+ step("r1: Shut/No Shut the interface r1-r2-eth1/r1-r0-eth0 from R1 to R2")
+ dut = "r1"
+ intf1 = TOPO["routers"]["r1"]["links"]["r2"]["interface"]
+ intf2 = TOPO["routers"]["r1"]["links"]["r0"]["interface"]
+ for intf in [intf1, intf2]:
+ shutdown_bringup_interface(tgen, dut, intf, False)
+ shutdown_bringup_interface(tgen, dut, intf, True)
+
+ step("r2: Shut the RP interface lo")
+ dut = "r2"
+ intf = "lo"
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ step("r1: Shut the interface r1-r2-eth1/r1-r3-eth2 towards RP")
+ intf3 = TOPO["routers"]["r1"]["links"]["r3"]["interface"]
+ for intf in [intf1, intf3]:
+ shutdown_bringup_interface(tgen, dut, intf, False)
+
+ step("r1: Verify (*, G) ip mroutes cleared")
+ dut = "r1"
+ iif = TOPO["routers"]["r1"]["links"]["r2"]["interface"]
+ oif = TOPO["routers"]["r1"]["links"]["r0"]["interface"]
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS_1, iif, oif, expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r1: (*,G) mroutes are not cleared after shut of R1 to R0 link\n Error: {}".format(
+ tc_name, result
+ )
+ )
+
+ step("r2: Verify (*, G) ip mroutes cleared")
+ dut = "r2"
+ iif = "lo"
+ oif = TOPO["routers"]["r2"]["links"]["r1"]["interface"]
+ result = verify_mroutes(tgen, dut, STAR, GROUP_ADDRESS_1, iif, oif, expected=False)
+ assert result is not True, (
+ "Testcase {} : Failed \n "
+ "r2: (*,G) mroutes are not cleared after shut of R1 to R0 link\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/multicast_pim_static_rp_topo1/test_multicast_pimv6_static_rp.py b/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pimv6_static_rp.py
deleted file mode 100755
index bd5473a51..000000000
--- a/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pimv6_static_rp.py
+++ /dev/null
@@ -1,414 +0,0 @@
-#!/usr/bin/env python
-
-#
-# Copyright (c) 2022 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 Multicast basic functionality:
-
-Topology:
-
- _______r2_____
- | |
- iperf | | iperf
- r0-----r1-------------r3-----r5
- | |
- |_____________|
- r4
-
-Test steps
-- Create topology (setup module)
-- Bring up topology
-
-TC_1 : Verify upstream interfaces(IIF) and join state are updated properly
- after adding and deleting the static RP
-TC_2 : Verify IIF and OIL in "show ip pim state" updated properly after
- adding and deleting the static RP
-TC_3: (*, G) Mroute entry are cleared when static RP gets deleted
-TC_4: Verify (*,G) prune is send towards the RP after deleting the static RP
-TC_24 : Verify (*,G) and (S,G) populated correctly when SPT and RPT share the
- same path
-"""
-
-import os
-import sys
-import json
-import time
-import pytest
-from time import sleep
-import datetime
-
-# Save the Current Working Directory to find configuration files.
-CWD = os.path.dirname(os.path.realpath(__file__))
-sys.path.append(os.path.join(CWD, "../"))
-sys.path.append(os.path.join(CWD, "../lib/"))
-
-# Required to instantiate the topology builder class.
-
-# pylint: disable=C0413
-# Import topogen and topotest helpers
-from lib.topogen import Topogen, get_topogen
-
-from lib.common_config import (
- start_topology,
- write_test_header,
- write_test_footer,
- reset_config_on_routers,
- step,
- shutdown_bringup_interface,
- kill_router_daemons,
- start_router_daemons,
- create_static_routes,
- check_router_status,
- socat_send_igmp_join_traffic,
- topo_daemons
-)
-from lib.pim import (
- create_pim_config,
- verify_igmp_groups,
- verify_upstream_iif,
- verify_join_state_and_timer,
- verify_mroutes,
- verify_pim_neighbors,
- verify_pim_interface_traffic,
- verify_pim_rp_info,
- verify_pim_state,
- clear_pim_interface_traffic,
- clear_igmp_interfaces,
- clear_pim_interfaces,
- clear_mroute,
- clear_mroute_verify,
-)
-from lib.topolog import logger
-from lib.topojson import build_topo_from_json, build_config_from_json
-
-# Global variables
-GROUP_RANGE_V6 = "ff08::/64"
-IGMP_JOIN_V6 = "ff08::1"
-STAR = "*"
-SOURCE = "Static"
-
-pytestmark = [pytest.mark.pimd]
-
-
-def build_topo(tgen):
- """Build function"""
-
- # 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: %s", testsuite_run_time)
- logger.info("=" * 40)
-
- topology = """
-
- _______r2_____
- | |
- iperf | | iperf
- r0-----r1-------------r3-----r5
- | |
- |_____________|
- r4
-
- """
- logger.info("Master Topology: \n %s", topology)
-
- logger.info("Running setup_module to create topology")
-
- # This function initiates the topology build with Topogen...
- json_file = "{}/multicast_pimv6_static_rp.json".format(CWD)
- tgen = Topogen(json_file, mod.__name__)
- global TOPO
- TOPO = tgen.json_topo
-
- # ... and here it calls Mininet initialization functions.
-
- # get list of daemons needs to be started for this suite.
- daemons = topo_daemons(tgen, TOPO)
-
- # Starting topology, create tmp files which are loaded to routers
- # to start daemons and then start routers
- start_topology(tgen, daemons)
-
- # Don"t run this test if we have any failure.
- if tgen.routers_have_failure():
- pytest.skip(tgen.errors)
-
- # Creating configuration from JSON
- build_config_from_json(tgen, TOPO)
-
- # Verify PIM neighbors
- result = verify_pim_neighbors(tgen, TOPO)
- assert result is True, "setup_module :Failed \n Error:" " {}".format(result)
-
- 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: %s", time.asctime(time.localtime(time.time())))
- logger.info("=" * 40)
-
-
-#####################################################
-#
-# Testcases
-#
-#####################################################
-
-
-def verify_state_incremented(state_before, state_after):
- """
- API to compare interface traffic state incrementing
-
- Parameters
- ----------
- * `state_before` : State dictionary for any particular instance
- * `state_after` : State dictionary for any particular instance
- """
-
- for router, state_data in state_before.items():
- for state, value in state_data.items():
- if state_before[router][state] >= state_after[router][state]:
- errormsg = (
- "[DUT: %s]: state %s value has not"
- " incremented, Initial value: %s, "
- "Current value: %s [FAILED!!]"
- % (
- router,
- state,
- state_before[router][state],
- state_after[router][state],
- )
- )
- return errormsg
-
- logger.info(
- "[DUT: %s]: State %s value is "
- "incremented, Initial value: %s, Current value: %s"
- " [PASSED!!]",
- router,
- state,
- state_before[router][state],
- state_after[router][state],
- )
-
- return True
-
-
-#####################################################
-
-def test_pimv6_add_delete_static_RP_p0(request):
- """
- TC_1: Verify upstream interfaces(IIF) and join state are updated
- properly after adding and deleting the static RP
- TC_2: Verify IIF and OIL in "show ip pim state" updated properly
- after adding and deleting the static RP
- TC_3: (*, G) Mroute entry are cleared when static RP gets deleted
- TC_4: Verify (*,G) prune is send towards the RP after deleting the
- static RP
-
- TOPOlogy used:
- r0------r1-----r2
- iperf DUT RP
- """
-
- 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():
- check_router_status(tgen)
-
- step("Shut link b/w R1 and R3 and R1 and R4 as per tescase topology")
- intf_r1_r3 = TOPO["routers"]["r1"]["links"]["r3"]["interface"]
- intf_r1_r4 = TOPO["routers"]["r1"]["links"]["r4"]["interface"]
- for intf in [intf_r1_r3, intf_r1_r4]:
- shutdown_bringup_interface(tgen, "r1", intf, ifaceaction=False)
-
- step("Enable PIM between r1 and r2")
- step("Enable MLD on r1 interface and send IGMP " "join (FF08::1) to r1")
- step("Configure r2 loopback interface as RP")
- input_dict = {
- "r2": {
- "pim6": {
- "rp": [
- {
- "rp_addr": TOPO["routers"]["r2"]["links"]["lo"]["ipv6"].split(
- "/"
- )[0],
- "group_addr_range": GROUP_RANGE_V6,
- }
- ]
- }
- }
- }
-
- result = create_pim_config(tgen, TOPO, input_dict)
- assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
-
- step("Verify show ip pim interface traffic without any mld join")
- state_dict = {
- "r1": {TOPO["routers"]["r1"]["links"]["r2"]["interface"]: ["pruneTx"]}
- }
-
- state_before = verify_pim_interface_traffic(tgen, state_dict, addr_type="ipv6")
- assert isinstance(
- state_before, dict
- ), "Testcase{} : Failed \n state_before is not dictionary \n " "Error: {}".format(
- tc_name, result
- )
-
- step("send mld join (FF08::1) to R1")
- intf = TOPO["routers"]["r0"]["links"]["r1"]["interface"]
- intf_ip = TOPO["routers"]["r0"]["links"]["r1"]["ipv6"].split("/")[0]
- result = socat_send_igmp_join_traffic(
- tgen, "r0", "UDP6-RECV", IGMP_JOIN_V6, intf, intf_ip, join=True
- )
- assert result is True, "Testcase {}: Failed Error: {}".format(tc_name, result)
-
- step("r1: Verify RP info")
- dut = "r1"
- oif = TOPO["routers"]["r1"]["links"]["r2"]["interface"]
- iif = TOPO["routers"]["r1"]["links"]["r0"]["interface"]
- rp_address = TOPO["routers"]["r2"]["links"]["lo"]["ipv6"].split("/")[0]
- result = verify_pim_rp_info(
- tgen, TOPO, dut, GROUP_RANGE_V6, oif, rp_address, SOURCE
- )
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify upstream IIF interface")
- result = verify_upstream_iif(tgen, dut, oif, STAR, IGMP_JOIN_V6)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify upstream join state and join timer")
- result = verify_join_state_and_timer(tgen, dut, oif, STAR, IGMP_JOIN_V6)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify PIM state")
- result = verify_pim_state(tgen, dut, oif, iif, IGMP_JOIN_V6)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Verify ip mroutes")
- result = verify_mroutes(tgen, dut, STAR, IGMP_JOIN_V6, oif, iif)
- assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result)
-
- step("r1: Delete RP configuration")
- input_dict = {
- "r2": {
- "pim6": {
- "rp": [
- {
- "rp_addr": TOPO["routers"]["r2"]["links"]["lo"]["ipv6"].split(
- "/"
- )[0],
- "group_addr_range": GROUP_RANGE_V6,
- "delete": True,
- }
- ]
- }
- }
- }
-
- result = create_pim_config(tgen, TOPO, input_dict)
- assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result)
-
- step("r1: Verify RP info")
- result = verify_pim_rp_info(
- tgen, TOPO, dut, GROUP_RANGE_V6, oif, rp_address, SOURCE, expected=False
- )
- assert (
- result is not True
- ), "Testcase {} :Failed \n " "RP: {} info is still present \n Error: {}".format(
- tc_name, rp_address, result
- )
-
- step("r1: Verify upstream IIF interface")
- result = verify_upstream_iif(tgen, dut, oif, STAR, IGMP_JOIN_V6, expected=False)
- assert result is not True, (
- "Testcase {} :Failed \n "
- "Upstream ({}, {}) is still in join state \n Error: {}".format(
- tc_name, STAR, IGMP_JOIN_V6, result
- )
- )
-
- step("r1: Verify upstream join state and join timer")
- result = verify_join_state_and_timer(
- tgen, dut, oif, STAR, IGMP_JOIN_V6, expected=False
- )
- assert result is not True, (
- "Testcase {} :Failed \n "
- "Upstream ({}, {}) timer is still running \n Error: {}".format(
- tc_name, STAR, IGMP_JOIN_V6, result
- )
- )
-
- step("r1: Verify PIM state")
- result = verify_pim_state(tgen, dut, oif, iif, IGMP_JOIN_V6, expected=False)
- assert result is not True, (
- "Testcase {} :Failed \n "
- "PIM state for group: {} is still Active \n Error: {}".format(
- tc_name, IGMP_JOIN_V6, result
- )
- )
-
- step("r1: Verify ip mroutes")
- result = verify_mroutes(tgen, dut, STAR, IGMP_JOIN_V6, oif, iif, expected=False)
- assert result is not True, (
- "Testcase {} :Failed \n "
- "mroute ({}, {}) is still present \n Error: {}".format(
- tc_name, STAR, IGMP_JOIN_V6, result
- )
- )
-
- step("r1: Verify show ip pim interface traffic without any IGMP join")
- state_after = verify_pim_interface_traffic(tgen, state_dict, addr_type="ipv6")
- assert isinstance(
- state_after, dict
- ), "Testcase{} : Failed \n state_before is not dictionary \n " "Error: {}".format(
- tc_name, result
- )
-
- result = verify_state_incremented(state_before, state_after)
- assert result is True, "Testcase{} : Failed Error: {}".format(tc_name, result)
-
- write_test_footer(tc_name)
-
-
-if __name__ == "__main__":
- args = ["-s"] + sys.argv[1:]
- sys.exit(pytest.main(args))
diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py b/tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py
index 3b84a99cd..e131fba0c 100644
--- a/tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py
+++ b/tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py
@@ -47,10 +47,12 @@ from lib.common_config import (
step,
create_interfaces_cfg,
topo_daemons,
+ retry,
+ run_frr_cmd,
)
from lib.topolog import logger
from lib.topojson import build_config_from_json
-from lib.topotest import frr_unicode
+from lib.topotest import frr_unicode, json_cmp
from lib.ospf import (
verify_ospf_interface,
@@ -378,6 +380,158 @@ def test_ospf_p2mp_tc1_p0(request):
write_test_footer(tc_name)
+@retry(retry_timeout=30)
+def verify_ospf_json(tgen, dut, input_dict, cmd="show ip ospf database json"):
+ del tgen
+ show_ospf_json = run_frr_cmd(dut, cmd, isjson=True)
+ if not bool(show_ospf_json):
+ return "ospf is not running"
+ result = json_cmp(show_ospf_json, input_dict)
+ return str(result) if result else None
+
+
+@pytest.mark.parametrize("tgen", [2], indirect=True)
+def test_ospf_nbrs(tgen):
+ db_full = {
+ "areas": {
+ "0.0.0.0": {
+ "routerLinkStates": [
+ {
+ "lsId": "100.1.1.0",
+ "advertisedRouter": "100.1.1.0",
+ "numOfRouterLinks": 6,
+ },
+ {
+ "lsId": "100.1.1.1",
+ "advertisedRouter": "100.1.1.1",
+ "numOfRouterLinks": 6,
+ },
+ {
+ "lsId": "100.1.1.2",
+ "advertisedRouter": "100.1.1.2",
+ "numOfRouterLinks": 6,
+ },
+ {
+ "lsId": "100.1.1.3",
+ "advertisedRouter": "100.1.1.3",
+ "numOfRouterLinks": 7,
+ },
+ ]
+ }
+ }
+ }
+ input = [
+ [
+ "r0",
+ "show ip ospf n json",
+ {
+ "neighbors": {
+ "100.1.1.1": [
+ {
+ "state": "Full/DROther",
+ }
+ ],
+ "100.1.1.2": [
+ {
+ "state": "Full/DROther",
+ }
+ ],
+ "100.1.1.3": [
+ {
+ "state": "Full/DROther",
+ }
+ ],
+ }
+ },
+ ],
+ [
+ "r1",
+ "show ip ospf n json",
+ {
+ "neighbors": {
+ "100.1.1.0": [
+ {
+ "state": "Full/DROther",
+ }
+ ],
+ "100.1.1.2": [
+ {
+ "state": "Full/DROther",
+ }
+ ],
+ "100.1.1.3": [
+ {
+ "state": "Full/DROther",
+ }
+ ],
+ }
+ },
+ ],
+ [
+ "r2",
+ "show ip ospf n json",
+ {
+ "neighbors": {
+ "100.1.1.0": [
+ {
+ "state": "Full/DROther",
+ }
+ ],
+ "100.1.1.1": [
+ {
+ "state": "Full/DROther",
+ }
+ ],
+ "100.1.1.3": [
+ {
+ "state": "Full/DROther",
+ }
+ ],
+ }
+ },
+ ],
+ [
+ "r3",
+ "show ip ospf n json",
+ {
+ "neighbors": {
+ "100.1.1.0": [
+ {
+ "state": "Full/DROther",
+ }
+ ],
+ "100.1.1.1": [
+ {
+ "state": "Full/DROther",
+ }
+ ],
+ "100.1.1.2": [
+ {
+ "state": "Full/DROther",
+ }
+ ],
+ }
+ },
+ ],
+ ["r0", "show ip ospf database json", db_full],
+ ["r1", "show ip ospf database json", db_full],
+ ["r2", "show ip ospf database json", db_full],
+ ["r3", "show ip ospf database json", db_full],
+ ["r0", "show ip ospf database json", db_full],
+ ["r0", "show ip ospf database router json", {}],
+ ["r0", "show ip ospf interface traffic json", {}],
+ ["r1", "show ip ospf interface traffic json", {}],
+ ["r2", "show ip ospf interface traffic json", {}],
+ ["r3", "show ip ospf interface traffic json", {}],
+ ]
+ for cmd_set in input:
+ step("test_ospf: %s - %s" % (cmd_set[0], cmd_set[1]))
+ assert (
+ verify_ospf_json(tgen, tgen.gears[cmd_set[0]], cmd_set[2], cmd_set[1])
+ is None
+ )
+
+
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))
diff --git a/tests/topotests/ospf_te_topo1/r1/zebra.conf b/tests/topotests/ospf_te_topo1/r1/zebra.conf
index 7c5dc3ffe..c47789a16 100644
--- a/tests/topotests/ospf_te_topo1/r1/zebra.conf
+++ b/tests/topotests/ospf_te_topo1/r1/zebra.conf
@@ -7,6 +7,7 @@ interface r1-eth0
link-params
metric 20
delay 10000
+ max-bw 10e+10
ava-bw 1.25e+08
enable
exit-link-params
diff --git a/tests/topotests/ospf_te_topo1/r2/zebra.conf b/tests/topotests/ospf_te_topo1/r2/zebra.conf
index 69e10191f..a9771f70c 100644
--- a/tests/topotests/ospf_te_topo1/r2/zebra.conf
+++ b/tests/topotests/ospf_te_topo1/r2/zebra.conf
@@ -25,6 +25,7 @@ interface r2-eth3
link-params
metric 30
delay 25000
+ max-bw 10e+10
use-bw 1.25e+8
enable
exit-link-params
diff --git a/tests/topotests/ospf_te_topo1/reference/ted_step1.json b/tests/topotests/ospf_te_topo1/reference/ted_step1.json
index d6bfca63f..18aee4ffa 100644
--- a/tests/topotests/ospf_te_topo1/reference/ted_step1.json
+++ b/tests/topotests/ospf_te_topo1/reference/ted_step1.json
@@ -68,32 +68,32 @@
"te-metric":20,
"local-address":"10.0.0.1",
"remote-address":"10.0.0.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":99999997952,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":10000,
@@ -111,32 +111,32 @@
"edge-attributes":{
"local-address":"10.0.0.2",
"remote-address":"10.0.0.1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -152,32 +152,32 @@
"edge-attributes":{
"local-address":"10.0.1.1",
"remote-address":"10.0.1.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -193,32 +193,32 @@
"edge-attributes":{
"local-address":"10.0.1.2",
"remote-address":"10.0.1.1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -235,32 +235,32 @@
"admin-group":32,
"local-address":"10.0.3.1",
"remote-address":"10.0.3.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -276,32 +276,32 @@
"edge-attributes":{
"local-address":"10.0.3.2",
"remote-address":"10.0.3.1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -317,32 +317,32 @@
"edge-attributes":{
"local-address":"10.0.4.1",
"remote-address":"10.0.4.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
},
@@ -371,32 +371,32 @@
"te-metric":30,
"local-address":"10.0.4.2",
"remote-address":"10.0.4.1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":99999997952,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":25000,
@@ -414,32 +414,32 @@
"edge-attributes":{
"te-metric":10,
"local-address":"10.0.5.1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"remote-asn":65535,
diff --git a/tests/topotests/ospf_te_topo1/reference/ted_step2.json b/tests/topotests/ospf_te_topo1/reference/ted_step2.json
index ec30af603..1ed727256 100644
--- a/tests/topotests/ospf_te_topo1/reference/ted_step2.json
+++ b/tests/topotests/ospf_te_topo1/reference/ted_step2.json
@@ -68,32 +68,32 @@
"te-metric":20,
"local-address":"10.0.0.1",
"remote-address":"10.0.0.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":99999997952,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":10000,
@@ -111,32 +111,32 @@
"edge-attributes":{
"local-address":"10.0.0.2",
"remote-address":"10.0.0.1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -153,32 +153,32 @@
"admin-group":32,
"local-address":"10.0.3.1",
"remote-address":"10.0.3.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -194,32 +194,32 @@
"edge-attributes":{
"local-address":"10.0.3.2",
"remote-address":"10.0.3.1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -235,32 +235,32 @@
"edge-attributes":{
"local-address":"10.0.4.1",
"remote-address":"10.0.4.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
},
@@ -289,32 +289,32 @@
"te-metric":30,
"local-address":"10.0.4.2",
"remote-address":"10.0.4.1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":99999997952,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":25000,
@@ -332,32 +332,32 @@
"edge-attributes":{
"te-metric":10,
"local-address":"10.0.5.1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"remote-asn":65535,
diff --git a/tests/topotests/ospf_te_topo1/reference/ted_step3.json b/tests/topotests/ospf_te_topo1/reference/ted_step3.json
index 853704b4f..0e79670c7 100644
--- a/tests/topotests/ospf_te_topo1/reference/ted_step3.json
+++ b/tests/topotests/ospf_te_topo1/reference/ted_step3.json
@@ -60,32 +60,32 @@
"te-metric":20,
"local-address":"10.0.0.1",
"remote-address":"10.0.0.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":99999997952,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":10000,
@@ -103,32 +103,32 @@
"edge-attributes":{
"local-address":"10.0.0.2",
"remote-address":"10.0.0.1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -145,32 +145,32 @@
"admin-group":32,
"local-address":"10.0.3.1",
"remote-address":"10.0.3.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -186,32 +186,32 @@
"edge-attributes":{
"local-address":"10.0.3.2",
"remote-address":"10.0.3.1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -227,32 +227,32 @@
"edge-attributes":{
"local-address":"10.0.4.1",
"remote-address":"10.0.4.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
},
@@ -281,32 +281,32 @@
"te-metric":30,
"local-address":"10.0.4.2",
"remote-address":"10.0.4.1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":99999997952,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":25000,
diff --git a/tests/topotests/ospf_te_topo1/reference/ted_step4.json b/tests/topotests/ospf_te_topo1/reference/ted_step4.json
index 0aa57713c..860dcb3f2 100644
--- a/tests/topotests/ospf_te_topo1/reference/ted_step4.json
+++ b/tests/topotests/ospf_te_topo1/reference/ted_step4.json
@@ -83,32 +83,32 @@
"te-metric":20,
"local-address":"10.0.0.1",
"remote-address":"10.0.0.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":99999997952,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":10000,
@@ -138,32 +138,32 @@
"edge-attributes":{
"local-address":"10.0.0.2",
"remote-address":"10.0.0.1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
},
@@ -192,32 +192,32 @@
"admin-group":32,
"local-address":"10.0.3.1",
"remote-address":"10.0.3.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -233,32 +233,32 @@
"edge-attributes":{
"local-address":"10.0.3.2",
"remote-address":"10.0.3.1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
},
@@ -286,32 +286,32 @@
"edge-attributes":{
"local-address":"10.0.4.1",
"remote-address":"10.0.4.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
},
@@ -340,32 +340,32 @@
"te-metric":30,
"local-address":"10.0.4.2",
"remote-address":"10.0.4.1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":99999997952,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":25000,
diff --git a/tests/topotests/ospf_te_topo1/reference/ted_step5.json b/tests/topotests/ospf_te_topo1/reference/ted_step5.json
index 07637f304..615a691c4 100644
--- a/tests/topotests/ospf_te_topo1/reference/ted_step5.json
+++ b/tests/topotests/ospf_te_topo1/reference/ted_step5.json
@@ -83,32 +83,32 @@
"te-metric":20,
"local-address":"10.0.0.1",
"remote-address":"10.0.0.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":99999997952,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":10000,
@@ -138,32 +138,32 @@
"edge-attributes":{
"local-address":"10.0.0.2",
"remote-address":"10.0.0.1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
},
@@ -191,32 +191,32 @@
"edge-attributes":{
"local-address":"10.0.1.1",
"remote-address":"10.0.1.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
},
@@ -244,32 +244,32 @@
"edge-attributes":{
"local-address":"10.0.1.2",
"remote-address":"10.0.1.1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
},
@@ -298,32 +298,32 @@
"admin-group":32,
"local-address":"10.0.3.1",
"remote-address":"10.0.3.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -339,32 +339,32 @@
"edge-attributes":{
"local-address":"10.0.3.2",
"remote-address":"10.0.3.1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
},
@@ -392,32 +392,32 @@
"edge-attributes":{
"local-address":"10.0.4.1",
"remote-address":"10.0.4.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
},
@@ -446,32 +446,32 @@
"te-metric":30,
"local-address":"10.0.4.2",
"remote-address":"10.0.4.1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":99999997952,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":25000,
diff --git a/tests/topotests/ospf_te_topo1/reference/ted_step6.json b/tests/topotests/ospf_te_topo1/reference/ted_step6.json
index e9eee96ff..3b84d2580 100644
--- a/tests/topotests/ospf_te_topo1/reference/ted_step6.json
+++ b/tests/topotests/ospf_te_topo1/reference/ted_step6.json
@@ -83,32 +83,32 @@
"te-metric":20,
"local-address":"10.0.0.1",
"remote-address":"10.0.0.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":99999997952,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":10000,
@@ -138,32 +138,32 @@
"edge-attributes":{
"local-address":"10.0.0.2",
"remote-address":"10.0.0.1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
},
@@ -191,32 +191,32 @@
"edge-attributes":{
"local-address":"10.0.1.1",
"remote-address":"10.0.1.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
},
@@ -244,32 +244,32 @@
"edge-attributes":{
"local-address":"10.0.1.2",
"remote-address":"10.0.1.1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
},
@@ -298,32 +298,32 @@
"admin-group":32,
"local-address":"10.0.3.1",
"remote-address":"10.0.3.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -339,32 +339,32 @@
"edge-attributes":{
"local-address":"10.0.3.2",
"remote-address":"10.0.3.1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
},
@@ -392,32 +392,32 @@
"edge-attributes":{
"local-address":"10.0.4.1",
"remote-address":"10.0.4.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":20000,
@@ -448,32 +448,32 @@
"te-metric":30,
"local-address":"10.0.4.2",
"remote-address":"10.0.4.1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":99999997952,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":25000
diff --git a/tests/topotests/ospf_te_topo1/reference/ted_step7.json b/tests/topotests/ospf_te_topo1/reference/ted_step7.json
index f912ae4a8..83f8a1d5d 100644
--- a/tests/topotests/ospf_te_topo1/reference/ted_step7.json
+++ b/tests/topotests/ospf_te_topo1/reference/ted_step7.json
@@ -64,32 +64,32 @@
"te-metric":20,
"local-address":"10.0.0.1",
"remote-address":"10.0.0.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":99999997952,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
],
"delay":10000,
@@ -119,32 +119,32 @@
"edge-attributes":{
"local-address":"10.0.0.2",
"remote-address":"10.0.0.1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
},
@@ -172,32 +172,32 @@
"edge-attributes":{
"local-address":"10.0.1.1",
"remote-address":"10.0.1.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
},
@@ -225,32 +225,32 @@
"edge-attributes":{
"local-address":"10.0.1.2",
"remote-address":"10.0.1.1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
},
@@ -279,32 +279,32 @@
"admin-group":32,
"local-address":"10.0.3.1",
"remote-address":"10.0.3.2",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
}
@@ -320,32 +320,32 @@
"edge-attributes":{
"local-address":"10.0.3.2",
"remote-address":"10.0.3.1",
- "max-link-bandwidth":176258176.0,
- "max-resv-link-bandwidth":176258176.0,
+ "max-link-bandwidth":1250000,
+ "max-resv-link-bandwidth":1250000,
"unreserved-bandwidth":[
{
- "class-type-0":176258176.0
+ "class-type-0":1250000
},
{
- "class-type-1":176258176.0
+ "class-type-1":1250000
},
{
- "class-type-2":176258176.0
+ "class-type-2":1250000
},
{
- "class-type-3":176258176.0
+ "class-type-3":1250000
},
{
- "class-type-4":176258176.0
+ "class-type-4":1250000
},
{
- "class-type-5":176258176.0
+ "class-type-5":1250000
},
{
- "class-type-6":176258176.0
+ "class-type-6":1250000
},
{
- "class-type-7":176258176.0
+ "class-type-7":1250000
}
]
},
diff --git a/tests/topotests/ospfapi/test_ospf_clientapi.py b/tests/topotests/ospfapi/test_ospf_clientapi.py
index 631c8025b..94c8c5c73 100644
--- a/tests/topotests/ospfapi/test_ospf_clientapi.py
+++ b/tests/topotests/ospfapi/test_ospf_clientapi.py
@@ -468,28 +468,449 @@ def _test_opaque_add_del(tgen, apibin):
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
)
- p = r1.popen([apibin, "-v", "add,11,232,3,ebadf00d"])
+ p = r1.popen(
+ [
+ apibin,
+ "-v",
+ "add,9,10.0.1.1,230,1",
+ "add,9,10.0.1.1,230,2,00000202",
+ "wait,1",
+ "add,10,1.2.3.4,231,1",
+ "add,10,1.2.3.4,231,2,0102030405060708",
+ "wait,1",
+ "add,11,232,1",
+ "add,11,232,2,ebadf00d",
+ "wait,20",
+ "del,9,10.0.1.1,230,2,0",
+ "del,10,1.2.3.4,231,2,1",
+ "del,11,232,1,1",
+ ]
+ )
+ add_input_dict = {
+ "areas": {
+ "1.2.3.4": {
+ "linkLocalOpaqueLsa": [
+ {
+ "lsId": "230.0.0.1",
+ "advertisedRouter": "192.168.0.1",
+ "sequenceNumber": "80000001",
+ "checksum": "6d5f",
+ },
+ {
+ "lsId": "230.0.0.2",
+ "advertisedRouter": "192.168.0.1",
+ "sequenceNumber": "80000001",
+ "checksum": "8142",
+ },
+ ],
+ "linkLocalOpaqueLsaCount": 2,
+ "areaLocalOpaqueLsa": [
+ {
+ "lsId": "231.0.0.1",
+ "advertisedRouter": "192.168.0.1",
+ "sequenceNumber": "80000001",
+ "checksum": "5278",
+ },
+ {
+ "lsId": "231.0.0.2",
+ "advertisedRouter": "192.168.0.1",
+ "sequenceNumber": "80000001",
+ "checksum": "6d30",
+ },
+ ],
+ "areaLocalOpaqueLsaCount": 2,
+ },
+ },
+ "asExternalOpaqueLsa": [
+ {
+ "lsId": "232.0.0.1",
+ "advertisedRouter": "192.168.0.1",
+ "sequenceNumber": "80000001",
+ "checksum": "5575",
+ },
+ {
+ "lsId": "232.0.0.2",
+ "advertisedRouter": "192.168.0.1",
+ "sequenceNumber": "80000001",
+ "checksum": "d05d",
+ },
+ ],
+ "asExternalOpaqueLsaCount": 2,
+ }
+
+ step("reachable: check for add LSAs")
+ json_cmd = "show ip ospf da json"
+ assert verify_ospf_database(tgen, r1, add_input_dict, json_cmd) is None
+ assert verify_ospf_database(tgen, r2, add_input_dict, json_cmd) is None
+
+ numcs = 3
+ json_cmds = [
+ "show ip ospf da opaque-link json",
+ "show ip ospf da opaque-area json",
+ "show ip ospf da opaque-as json",
+ ]
+ add_detail_input_dict = [
+ {
+ "linkLocalOpaqueLsa": {
+ "areas": {
+ "1.2.3.4": [
+ {
+ "linkStateId": "230.0.0.1",
+ "advertisingRouter": "192.168.0.1",
+ "lsaSeqNumber": "80000001",
+ "checksum": "6d5f",
+ "length": 20,
+ "opaqueDataLength": 0,
+ },
+ {
+ "linkStateId": "230.0.0.2",
+ "advertisingRouter": "192.168.0.1",
+ "lsaSeqNumber": "80000001",
+ "checksum": "8142",
+ "length": 24,
+ "opaqueId": 2,
+ "opaqueDataLength": 4,
+ },
+ ]
+ }
+ }
+ },
+ {
+ "areaLocalOpaqueLsa": {
+ "areas": {
+ "1.2.3.4": [
+ {
+ "linkStateId": "231.0.0.1",
+ "advertisingRouter": "192.168.0.1",
+ "lsaSeqNumber": "80000001",
+ "checksum": "5278",
+ "length": 20,
+ "opaqueDataLength": 0,
+ },
+ {
+ "linkStateId": "231.0.0.2",
+ "advertisingRouter": "192.168.0.1",
+ "lsaSeqNumber": "80000001",
+ "checksum": "6d30",
+ "length": 28,
+ "opaqueDataLength": 8,
+ },
+ ],
+ },
+ },
+ },
+ {
+ "asExternalOpaqueLsa": [
+ {
+ "linkStateId": "232.0.0.1",
+ "advertisingRouter": "192.168.0.1",
+ "lsaSeqNumber": "80000001",
+ "checksum": "5575",
+ "length": 20,
+ "opaqueDataLength": 0,
+ },
+ {
+ "linkStateId": "232.0.0.2",
+ "advertisingRouter": "192.168.0.1",
+ "lsaSeqNumber": "80000001",
+ "checksum": "d05d",
+ "length": 24,
+ "opaqueDataLength": 4,
+ },
+ ],
+ },
+ ]
+ i = 0
+ while i < numcs:
+ step("reachable: check for add LSA details: %s" % json_cmds[i])
+ assert (
+ verify_ospf_database(tgen, r1, add_detail_input_dict[i], json_cmds[i])
+ is None
+ )
+ assert (
+ verify_ospf_database(tgen, r2, add_detail_input_dict[i], json_cmds[i])
+ is None
+ )
+ i += 1
# Wait for add notification
# RECV: LSA update msg for LSA 232.0.0.3 in area 0.0.0.0 seq 0x80000001 len 24 age 9
- ls_id = "232.0.0.3"
- waitfor = "RECV:.*update msg.*LSA {}.*age ([0-9]+)".format(ls_id)
- _ = _wait_output(pread, waitfor)
+ ls_ids = [
+ "230.0.0.1",
+ "230.0.0.2",
+ "231.0.0.1",
+ "231.0.0.2",
+ "232.0.0.1",
+ "232.0.0.2",
+ ]
+ for ls_id in ls_ids:
+ step("reachable: check for API add notification: %s" % ls_id)
+ waitfor = "RECV:.*update msg.*LSA {}.*age ([0-9]+)".format(ls_id)
+ _ = _wait_output(pread, waitfor)
+
+ del_input_dict = {
+ "areas": {
+ "1.2.3.4": {
+ "linkLocalOpaqueLsa": [
+ {
+ "lsId": "230.0.0.1",
+ "advertisedRouter": "192.168.0.1",
+ "sequenceNumber": "80000001",
+ "checksum": "6d5f",
+ },
+ {
+ "lsId": "230.0.0.2",
+ "advertisedRouter": "192.168.0.1",
+ "lsaAge": 3600,
+ "sequenceNumber": "80000001",
+ "checksum": "8142",
+ },
+ ],
+ "linkLocalOpaqueLsaCount": 2,
+ "areaLocalOpaqueLsa": [
+ {
+ "lsId": "231.0.0.1",
+ "advertisedRouter": "192.168.0.1",
+ "sequenceNumber": "80000001",
+ "checksum": "5278",
+ },
+ {
+ "lsId": "231.0.0.2",
+ "advertisedRouter": "192.168.0.1",
+ "lsaAge": 3600,
+ "sequenceNumber": "80000002",
+ "checksum": "4682",
+ },
+ ],
+ "areaLocalOpaqueLsaCount": 2,
+ },
+ },
+ "asExternalOpaqueLsa": [
+ {
+ "lsId": "232.0.0.1",
+ "advertisedRouter": "192.168.0.1",
+ "lsaAge": 3600,
+ "sequenceNumber": "80000001",
+ "checksum": "5575",
+ },
+ {
+ "lsId": "232.0.0.2",
+ "advertisedRouter": "192.168.0.1",
+ "sequenceNumber": "80000001",
+ "checksum": "d05d",
+ },
+ ],
+ "asExternalOpaqueLsaCount": 2,
+ }
+
+ step("reachable: check for explicit withdrawal LSAs")
+ json_cmd = "show ip ospf da json"
+ assert verify_ospf_database(tgen, r1, del_input_dict, json_cmd) is None
+ assert verify_ospf_database(tgen, r2, del_input_dict, json_cmd) is None
+
+ del_detail_input_dict = [
+ {
+ "linkLocalOpaqueLsa": {
+ "areas": {
+ "1.2.3.4": [
+ {
+ "linkStateId": "230.0.0.1",
+ "advertisingRouter": "192.168.0.1",
+ "lsaSeqNumber": "80000001",
+ "checksum": "6d5f",
+ "length": 20,
+ "opaqueDataLength": 0,
+ },
+ {
+ "linkStateId": "230.0.0.2",
+ "advertisingRouter": "192.168.0.1",
+ "lsaAge": 3600,
+ "lsaSeqNumber": "80000001",
+ "checksum": "8142",
+ "length": 24,
+ "opaqueId": 2,
+ "opaqueDataLength": 4,
+ },
+ ]
+ }
+ }
+ },
+ {
+ "areaLocalOpaqueLsa": {
+ "areas": {
+ "1.2.3.4": [
+ {
+ "linkStateId": "231.0.0.1",
+ "advertisingRouter": "192.168.0.1",
+ "lsaSeqNumber": "80000001",
+ "checksum": "5278",
+ "length": 20,
+ "opaqueDataLength": 0,
+ },
+ {
+ "lsaAge": 3600,
+ "linkStateId": "231.0.0.2",
+ "advertisingRouter": "192.168.0.1",
+ "lsaSeqNumber": "80000002",
+ "checksum": "4682",
+ # data removed
+ "length": 20,
+ "opaqueDataLength": 0,
+ },
+ ],
+ },
+ },
+ },
+ {
+ "asExternalOpaqueLsa": [
+ {
+ "linkStateId": "232.0.0.1",
+ "advertisingRouter": "192.168.0.1",
+ "lsaAge": 3600,
+ "lsaSeqNumber": "80000001",
+ "checksum": "5575",
+ "length": 20,
+ "opaqueDataLength": 0,
+ },
+ {
+ "linkStateId": "232.0.0.2",
+ "advertisingRouter": "192.168.0.1",
+ "lsaSeqNumber": "80000001",
+ "checksum": "d05d",
+ "length": 24,
+ "opaqueDataLength": 4,
+ },
+ ],
+ },
+ ]
+ i = 0
+ while i < numcs:
+ step("reachable: check for delete LSA details: %s" % json_cmds[i])
+ assert (
+ verify_ospf_database(tgen, r1, del_detail_input_dict[i], json_cmds[i])
+ is None
+ )
+ assert (
+ verify_ospf_database(tgen, r2, del_detail_input_dict[i], json_cmds[i])
+ is None
+ )
+ i += 1
p.terminate()
if p.wait():
comm_error(p)
+ del_detail_input_dict = [
+ {
+ "linkLocalOpaqueLsa": {
+ "areas": {
+ "1.2.3.4": [
+ {
+ "linkStateId": "230.0.0.1",
+ "advertisingRouter": "192.168.0.1",
+ "lsaAge": 3600,
+ "lsaSeqNumber": "80000001",
+ "checksum": "6d5f",
+ "length": 20,
+ "opaqueDataLength": 0,
+ },
+ {
+ "linkStateId": "230.0.0.2",
+ "advertisingRouter": "192.168.0.1",
+ "lsaAge": 3600,
+ "lsaSeqNumber": "80000001",
+ "checksum": "8142",
+ "length": 24,
+ "opaqueId": 2,
+ "opaqueDataLength": 4,
+ },
+ ]
+ }
+ }
+ },
+ {
+ "areaLocalOpaqueLsa": {
+ "areas": {
+ "1.2.3.4": [
+ {
+ "lsaAge": 3600,
+ "linkStateId": "231.0.0.1",
+ "advertisingRouter": "192.168.0.1",
+ "lsaSeqNumber": "80000001",
+ "checksum": "5278",
+ "length": 20,
+ "opaqueDataLength": 0,
+ },
+ {
+ "lsaAge": 3600,
+ "linkStateId": "231.0.0.2",
+ "advertisingRouter": "192.168.0.1",
+ "lsaSeqNumber": "80000002",
+ "checksum": "4682",
+ # data removed
+ "length": 20,
+ "opaqueDataLength": 0,
+ },
+ ],
+ },
+ },
+ },
+ {
+ "asExternalOpaqueLsa": [
+ {
+ "linkStateId": "232.0.0.1",
+ "advertisingRouter": "192.168.0.1",
+ "lsaAge": 3600,
+ "lsaSeqNumber": "80000001",
+ "checksum": "5575",
+ "length": 20,
+ "opaqueDataLength": 0,
+ },
+ {
+ "linkStateId": "232.0.0.2",
+ "advertisingRouter": "192.168.0.1",
+ "lsaAge": 3600,
+ "lsaSeqNumber": "80000001",
+ "checksum": "d05d",
+ "length": 24,
+ "opaqueDataLength": 4,
+ },
+ ],
+ },
+ ]
+ i = 0
+ while i < numcs:
+ step(
+ "reachable: check for post API shutdown delete LSA details: %s"
+ % json_cmds[i]
+ )
+ assert (
+ verify_ospf_database(tgen, r1, del_detail_input_dict[i], json_cmds[i])
+ is None
+ )
+ assert (
+ verify_ospf_database(tgen, r2, del_detail_input_dict[i], json_cmds[i])
+ is None
+ )
+ i += 1
+
# step("reachable: check for flush/age out")
# # Wait for max age notification
# waitfor = "RECV:.*update msg.*LSA {}.*age 3600".format(ls_id)
# _wait_output(pread, waitfor)
-
- step("reachable: check for delete")
- # Wait for delete notification
- waitfor = "RECV:.*delete msg.*LSA {}.*".format(ls_id)
- _wait_output(pread, waitfor)
+ ls_ids = [
+ "230.0.0.2",
+ "231.0.0.2",
+ "232.0.0.1",
+ "230.0.0.1",
+ "231.0.0.1",
+ "232.0.0.2",
+ ]
+ for ls_id in ls_ids:
+ step("reachable: check for API delete notification: %s" % ls_id)
+ waitfor = "RECV:.*delete msg.*LSA {}.*age".format(ls_id)
+ _ = _wait_output(pread, waitfor)
except Exception:
if p:
p.terminate()
diff --git a/tests/topotests/pytest.ini b/tests/topotests/pytest.ini
index 7dd13935b..6986e3051 100644
--- a/tests/topotests/pytest.ini
+++ b/tests/topotests/pytest.ini
@@ -46,6 +46,7 @@ markers =
pathd: Tests that run against PATHD
pbrd: Tests that run against PBRD
pimd: Tests that run against PIMD
+ pim6d: Tests that run against PIM6D
ripd: Tests that run against RIPD
ripngd: Tests that run against RIPNGD
sharpd: Tests that run against SHARPD
diff --git a/tests/topotests/srv6_locator_custom_bits_length/__init__.py b/tests/topotests/srv6_locator_custom_bits_length/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/srv6_locator_custom_bits_length/__init__.py
diff --git a/tests/topotests/srv6_locator_custom_bits_length/expected_chunks1.json b/tests/topotests/srv6_locator_custom_bits_length/expected_chunks1.json
new file mode 100644
index 000000000..fe51488c7
--- /dev/null
+++ b/tests/topotests/srv6_locator_custom_bits_length/expected_chunks1.json
@@ -0,0 +1 @@
+[]
diff --git a/tests/topotests/srv6_locator_custom_bits_length/expected_chunks2.json b/tests/topotests/srv6_locator_custom_bits_length/expected_chunks2.json
new file mode 100644
index 000000000..9f34c58ff
--- /dev/null
+++ b/tests/topotests/srv6_locator_custom_bits_length/expected_chunks2.json
@@ -0,0 +1,8 @@
+[
+ {
+ "name": "loc1",
+ "chunks": [
+ "2001:db8:1::/64"
+ ]
+ }
+]
diff --git a/tests/topotests/srv6_locator_custom_bits_length/expected_chunks3.json b/tests/topotests/srv6_locator_custom_bits_length/expected_chunks3.json
new file mode 100644
index 000000000..fe51488c7
--- /dev/null
+++ b/tests/topotests/srv6_locator_custom_bits_length/expected_chunks3.json
@@ -0,0 +1 @@
+[]
diff --git a/tests/topotests/srv6_locator_custom_bits_length/expected_chunks4.json b/tests/topotests/srv6_locator_custom_bits_length/expected_chunks4.json
new file mode 100644
index 000000000..0d4f101c7
--- /dev/null
+++ b/tests/topotests/srv6_locator_custom_bits_length/expected_chunks4.json
@@ -0,0 +1,2 @@
+[
+]
diff --git a/tests/topotests/srv6_locator_custom_bits_length/expected_chunks5.json b/tests/topotests/srv6_locator_custom_bits_length/expected_chunks5.json
new file mode 100644
index 000000000..0d4f101c7
--- /dev/null
+++ b/tests/topotests/srv6_locator_custom_bits_length/expected_chunks5.json
@@ -0,0 +1,2 @@
+[
+]
diff --git a/tests/topotests/srv6_locator_custom_bits_length/expected_chunks6.json b/tests/topotests/srv6_locator_custom_bits_length/expected_chunks6.json
new file mode 100644
index 000000000..0d4f101c7
--- /dev/null
+++ b/tests/topotests/srv6_locator_custom_bits_length/expected_chunks6.json
@@ -0,0 +1,2 @@
+[
+]
diff --git a/tests/topotests/srv6_locator_custom_bits_length/expected_locators1.json b/tests/topotests/srv6_locator_custom_bits_length/expected_locators1.json
new file mode 100644
index 000000000..e89a56a8e
--- /dev/null
+++ b/tests/topotests/srv6_locator_custom_bits_length/expected_locators1.json
@@ -0,0 +1,34 @@
+{
+ "locators":[
+ {
+ "name": "loc1",
+ "prefix": "2001:db8:1::/64",
+ "blockBitsLength": 40,
+ "nodeBitsLength": 24,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "statusUp": true,
+ "chunks": [
+ {
+ "prefix": "2001:db8:1::/64",
+ "proto": "system"
+ }
+ ]
+ },
+ {
+ "name": "loc2",
+ "prefix": "2001:db8:2::/48",
+ "blockBitsLength": 24,
+ "nodeBitsLength": 24,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "statusUp": true,
+ "chunks": [
+ {
+ "prefix": "2001:db8:2::/48",
+ "proto": "system"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_locator_custom_bits_length/expected_locators2.json b/tests/topotests/srv6_locator_custom_bits_length/expected_locators2.json
new file mode 100644
index 000000000..f2ca09a43
--- /dev/null
+++ b/tests/topotests/srv6_locator_custom_bits_length/expected_locators2.json
@@ -0,0 +1,34 @@
+{
+ "locators":[
+ {
+ "name": "loc1",
+ "prefix": "2001:db8:1::/64",
+ "blockBitsLength": 40,
+ "nodeBitsLength": 24,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "statusUp": true,
+ "chunks": [
+ {
+ "prefix": "2001:db8:1::/64",
+ "proto": "sharp"
+ }
+ ]
+ },
+ {
+ "name": "loc2",
+ "prefix": "2001:db8:2::/48",
+ "blockBitsLength": 24,
+ "nodeBitsLength": 24,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "statusUp": true,
+ "chunks": [
+ {
+ "prefix": "2001:db8:2::/48",
+ "proto": "system"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_locator_custom_bits_length/expected_locators3.json b/tests/topotests/srv6_locator_custom_bits_length/expected_locators3.json
new file mode 100644
index 000000000..e89a56a8e
--- /dev/null
+++ b/tests/topotests/srv6_locator_custom_bits_length/expected_locators3.json
@@ -0,0 +1,34 @@
+{
+ "locators":[
+ {
+ "name": "loc1",
+ "prefix": "2001:db8:1::/64",
+ "blockBitsLength": 40,
+ "nodeBitsLength": 24,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "statusUp": true,
+ "chunks": [
+ {
+ "prefix": "2001:db8:1::/64",
+ "proto": "system"
+ }
+ ]
+ },
+ {
+ "name": "loc2",
+ "prefix": "2001:db8:2::/48",
+ "blockBitsLength": 24,
+ "nodeBitsLength": 24,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "statusUp": true,
+ "chunks": [
+ {
+ "prefix": "2001:db8:2::/48",
+ "proto": "system"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_locator_custom_bits_length/expected_locators4.json b/tests/topotests/srv6_locator_custom_bits_length/expected_locators4.json
new file mode 100644
index 000000000..4c75d7ff5
--- /dev/null
+++ b/tests/topotests/srv6_locator_custom_bits_length/expected_locators4.json
@@ -0,0 +1,49 @@
+{
+ "locators":[
+ {
+ "name": "loc1",
+ "prefix": "2001:db8:1::/64",
+ "blockBitsLength": 40,
+ "nodeBitsLength": 24,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "statusUp": true,
+ "chunks": [
+ {
+ "prefix": "2001:db8:1::/64",
+ "proto": "system"
+ }
+ ]
+ },
+ {
+ "name": "loc2",
+ "prefix": "2001:db8:2::/48",
+ "blockBitsLength": 24,
+ "nodeBitsLength": 24,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "statusUp": true,
+ "chunks": [
+ {
+ "prefix": "2001:db8:2::/48",
+ "proto": "system"
+ }
+ ]
+ },
+ {
+ "name": "loc3",
+ "prefix": "2001:db8:3::/48",
+ "blockBitsLength": 32,
+ "nodeBitsLength": 16,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "statusUp": true,
+ "chunks": [
+ {
+ "prefix": "2001:db8:3::/48",
+ "proto": "system"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_locator_custom_bits_length/expected_locators5.json b/tests/topotests/srv6_locator_custom_bits_length/expected_locators5.json
new file mode 100644
index 000000000..a01d313b6
--- /dev/null
+++ b/tests/topotests/srv6_locator_custom_bits_length/expected_locators5.json
@@ -0,0 +1,34 @@
+{
+ "locators":[
+ {
+ "name": "loc2",
+ "prefix": "2001:db8:2::/48",
+ "blockBitsLength": 24,
+ "nodeBitsLength": 24,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "statusUp": true,
+ "chunks": [
+ {
+ "prefix": "2001:db8:2::/48",
+ "proto": "system"
+ }
+ ]
+ },
+ {
+ "name": "loc3",
+ "prefix": "2001:db8:3::/48",
+ "statusUp": true,
+ "blockBitsLength": 32,
+ "nodeBitsLength": 16,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "chunks":[
+ {
+ "prefix": "2001:db8:3::/48",
+ "proto": "system"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_locator_custom_bits_length/expected_locators6.json b/tests/topotests/srv6_locator_custom_bits_length/expected_locators6.json
new file mode 100644
index 000000000..6e1b993ca
--- /dev/null
+++ b/tests/topotests/srv6_locator_custom_bits_length/expected_locators6.json
@@ -0,0 +1,4 @@
+{
+ "locators":[
+ ]
+}
diff --git a/tests/topotests/srv6_locator_custom_bits_length/r1/setup.sh b/tests/topotests/srv6_locator_custom_bits_length/r1/setup.sh
new file mode 100644
index 000000000..36ed713f2
--- /dev/null
+++ b/tests/topotests/srv6_locator_custom_bits_length/r1/setup.sh
@@ -0,0 +1,2 @@
+ip link add dummy0 type dummy
+ip link set dummy0 up
diff --git a/tests/topotests/srv6_locator_custom_bits_length/r1/sharpd.conf b/tests/topotests/srv6_locator_custom_bits_length/r1/sharpd.conf
new file mode 100644
index 000000000..d46085935
--- /dev/null
+++ b/tests/topotests/srv6_locator_custom_bits_length/r1/sharpd.conf
@@ -0,0 +1,7 @@
+hostname r1
+!
+log stdout notifications
+log monitor notifications
+log commands
+log file sharpd.log debugging
+!
diff --git a/tests/topotests/srv6_locator_custom_bits_length/r1/zebra.conf b/tests/topotests/srv6_locator_custom_bits_length/r1/zebra.conf
new file mode 100644
index 000000000..30a520b79
--- /dev/null
+++ b/tests/topotests/srv6_locator_custom_bits_length/r1/zebra.conf
@@ -0,0 +1,22 @@
+hostname r1
+!
+! debug zebra events
+! debug zebra rib detailed
+!
+log stdout notifications
+log monitor notifications
+log commands
+log file zebra.log debugging
+!
+segment-routing
+ srv6
+ locators
+ locator loc1
+ prefix 2001:db8:1::/64
+ !
+ locator loc2
+ prefix 2001:db8:2::/48
+ !
+ !
+ !
+!
diff --git a/tests/topotests/srv6_locator_custom_bits_length/test_srv6_locator.py b/tests/topotests/srv6_locator_custom_bits_length/test_srv6_locator.py
new file mode 100755
index 000000000..ecc085637
--- /dev/null
+++ b/tests/topotests/srv6_locator_custom_bits_length/test_srv6_locator.py
@@ -0,0 +1,160 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2022, University of Rome Tor Vergata
+# Authored by Carmine Scarpitta <carmine.scarpitta@uniroma2.it>
+#
+# 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_srv6_manager.py:
+Test for SRv6 manager on zebra
+"""
+
+import os
+import sys
+import json
+import pytest
+import functools
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+pytestmark = [pytest.mark.bgpd, pytest.mark.sharpd]
+
+
+def open_json_file(filename):
+ try:
+ with open(filename, "r") as f:
+ return json.load(f)
+ except IOError:
+ assert False, "Could not read file {}".format(filename)
+
+
+def setup_module(mod):
+ tgen = Topogen({None: "r1"}, mod.__name__)
+ tgen.start_topology()
+ for rname, router in tgen.routers().items():
+ router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname))
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_SHARP, os.path.join(CWD, "{}/sharpd.conf".format(rname))
+ )
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_srv6():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ router = tgen.gears["r1"]
+
+ def _check_srv6_locator(router, expected_locator_file):
+ logger.info("checking zebra locator status")
+ output = json.loads(router.vtysh_cmd("show segment-routing srv6 locator json"))
+ expected = open_json_file("{}/{}".format(CWD, expected_locator_file))
+ return topotest.json_cmp(output, expected)
+
+ def _check_sharpd_chunk(router, expected_chunk_file):
+ logger.info("checking sharpd locator chunk status")
+ output = json.loads(router.vtysh_cmd("show sharp segment-routing srv6 json"))
+ expected = open_json_file("{}/{}".format(CWD, expected_chunk_file))
+ return topotest.json_cmp(output, expected)
+
+ def check_srv6_locator(router, expected_file):
+ func = functools.partial(_check_srv6_locator, router, expected_file)
+ success, result = topotest.run_and_expect(func, None, count=5, wait=0.5)
+ assert result is None, "Failed"
+
+ def check_sharpd_chunk(router, expected_file):
+ func = functools.partial(_check_sharpd_chunk, router, expected_file)
+ success, result = topotest.run_and_expect(func, None, count=5, wait=0.5)
+ assert result is None, "Failed"
+
+ # FOR DEVELOPER:
+ # If you want to stop some specific line and start interactive shell,
+ # please use tgen.mininet_cli() to start it.
+
+ logger.info("Test1 for Locator Configuration")
+ check_srv6_locator(router, "expected_locators1.json")
+ check_sharpd_chunk(router, "expected_chunks1.json")
+
+ logger.info("Test2 get chunk for locator loc1")
+ router.vtysh_cmd("sharp srv6-manager get-locator-chunk loc1")
+ check_srv6_locator(router, "expected_locators2.json")
+ check_sharpd_chunk(router, "expected_chunks2.json")
+
+ logger.info("Test3 release chunk for locator loc1")
+ router.vtysh_cmd("sharp srv6-manager release-locator-chunk loc1")
+ check_srv6_locator(router, "expected_locators3.json")
+ check_sharpd_chunk(router, "expected_chunks3.json")
+
+ logger.info("Test4 additional locator loc3")
+ router.vtysh_cmd(
+ """
+ configure terminal
+ segment-routing
+ srv6
+ locators
+ locator loc3
+ prefix 2001:db8:3::/48 func-bits 16 block-len 32 node-len 16
+ """
+ )
+ check_srv6_locator(router, "expected_locators4.json")
+ check_sharpd_chunk(router, "expected_chunks4.json")
+
+ logger.info("Test5 delete locator and chunk is released automatically")
+ router.vtysh_cmd(
+ """
+ configure terminal
+ segment-routing
+ srv6
+ locators
+ no locator loc1
+ """
+ )
+ check_srv6_locator(router, "expected_locators5.json")
+ check_sharpd_chunk(router, "expected_chunks5.json")
+
+ logger.info("Test6 delete srv6 all configuration")
+ router.vtysh_cmd(
+ """
+ configure terminal
+ segment-routing
+ no srv6
+ """
+ )
+ check_srv6_locator(router, "expected_locators6.json")
+ check_sharpd_chunk(router, "expected_chunks6.json")
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/srv6_locator_usid/__init__.py b/tests/topotests/srv6_locator_usid/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/__init__.py
diff --git a/tests/topotests/srv6_locator_usid/expected_chunks_1.json b/tests/topotests/srv6_locator_usid/expected_chunks_1.json
new file mode 100644
index 000000000..fe51488c7
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/expected_chunks_1.json
@@ -0,0 +1 @@
+[]
diff --git a/tests/topotests/srv6_locator_usid/expected_chunks_2.json b/tests/topotests/srv6_locator_usid/expected_chunks_2.json
new file mode 100644
index 000000000..304d73807
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/expected_chunks_2.json
@@ -0,0 +1,8 @@
+[
+ {
+ "name": "loc1",
+ "chunks": [
+ "fc00:0:1::/48"
+ ]
+ }
+]
diff --git a/tests/topotests/srv6_locator_usid/expected_chunks_3.json b/tests/topotests/srv6_locator_usid/expected_chunks_3.json
new file mode 100644
index 000000000..fe51488c7
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/expected_chunks_3.json
@@ -0,0 +1 @@
+[]
diff --git a/tests/topotests/srv6_locator_usid/expected_chunks_4.json b/tests/topotests/srv6_locator_usid/expected_chunks_4.json
new file mode 100644
index 000000000..fe51488c7
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/expected_chunks_4.json
@@ -0,0 +1 @@
+[]
diff --git a/tests/topotests/srv6_locator_usid/expected_chunks_5.json b/tests/topotests/srv6_locator_usid/expected_chunks_5.json
new file mode 100644
index 000000000..0d4f101c7
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/expected_chunks_5.json
@@ -0,0 +1,2 @@
+[
+]
diff --git a/tests/topotests/srv6_locator_usid/expected_chunks_6.json b/tests/topotests/srv6_locator_usid/expected_chunks_6.json
new file mode 100644
index 000000000..0d4f101c7
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/expected_chunks_6.json
@@ -0,0 +1,2 @@
+[
+]
diff --git a/tests/topotests/srv6_locator_usid/expected_chunks_7.json b/tests/topotests/srv6_locator_usid/expected_chunks_7.json
new file mode 100644
index 000000000..0d4f101c7
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/expected_chunks_7.json
@@ -0,0 +1,2 @@
+[
+]
diff --git a/tests/topotests/srv6_locator_usid/expected_chunks_8.json b/tests/topotests/srv6_locator_usid/expected_chunks_8.json
new file mode 100644
index 000000000..0d4f101c7
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/expected_chunks_8.json
@@ -0,0 +1,2 @@
+[
+]
diff --git a/tests/topotests/srv6_locator_usid/expected_locators_1.json b/tests/topotests/srv6_locator_usid/expected_locators_1.json
new file mode 100644
index 000000000..c0eeacc09
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/expected_locators_1.json
@@ -0,0 +1,20 @@
+{
+ "locators":[
+ {
+ "name": "loc1",
+ "prefix": "fc00:0:1::/48",
+ "blockBitsLength": 32,
+ "nodeBitsLength": 16,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "behavior": "usid",
+ "statusUp": true,
+ "chunks": [
+ {
+ "prefix": "fc00:0:1::/48",
+ "proto": "system"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_locator_usid/expected_locators_2.json b/tests/topotests/srv6_locator_usid/expected_locators_2.json
new file mode 100644
index 000000000..38a6739d6
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/expected_locators_2.json
@@ -0,0 +1,20 @@
+{
+ "locators":[
+ {
+ "name": "loc1",
+ "prefix": "fc00:0:1::/48",
+ "blockBitsLength": 32,
+ "nodeBitsLength": 16,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "behavior": "usid",
+ "statusUp": true,
+ "chunks": [
+ {
+ "prefix": "fc00:0:1::/48",
+ "proto": "sharp"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_locator_usid/expected_locators_3.json b/tests/topotests/srv6_locator_usid/expected_locators_3.json
new file mode 100644
index 000000000..c0eeacc09
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/expected_locators_3.json
@@ -0,0 +1,20 @@
+{
+ "locators":[
+ {
+ "name": "loc1",
+ "prefix": "fc00:0:1::/48",
+ "blockBitsLength": 32,
+ "nodeBitsLength": 16,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "behavior": "usid",
+ "statusUp": true,
+ "chunks": [
+ {
+ "prefix": "fc00:0:1::/48",
+ "proto": "system"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_locator_usid/expected_locators_4.json b/tests/topotests/srv6_locator_usid/expected_locators_4.json
new file mode 100644
index 000000000..b1528ff11
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/expected_locators_4.json
@@ -0,0 +1,35 @@
+{
+ "locators":[
+ {
+ "name": "loc1",
+ "prefix": "fc00:0:1::/48",
+ "blockBitsLength": 32,
+ "nodeBitsLength": 16,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "behavior": "usid",
+ "statusUp": true,
+ "chunks": [
+ {
+ "prefix": "fc00:0:1::/48",
+ "proto": "system"
+ }
+ ]
+ },
+ {
+ "name": "loc2",
+ "prefix": "fc00:0:2::/48",
+ "blockBitsLength": 32,
+ "nodeBitsLength": 16,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "statusUp": true,
+ "chunks": [
+ {
+ "prefix": "fc00:0:2::/48",
+ "proto": "system"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_locator_usid/expected_locators_5.json b/tests/topotests/srv6_locator_usid/expected_locators_5.json
new file mode 100644
index 000000000..b6acc238a
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/expected_locators_5.json
@@ -0,0 +1,36 @@
+{
+ "locators":[
+ {
+ "name": "loc1",
+ "prefix": "fc00:0:1::/48",
+ "blockBitsLength": 32,
+ "nodeBitsLength": 16,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "behavior": "usid",
+ "statusUp": true,
+ "chunks": [
+ {
+ "prefix": "fc00:0:1::/48",
+ "proto": "system"
+ }
+ ]
+ },
+ {
+ "name": "loc2",
+ "prefix": "fc00:0:2::/48",
+ "blockBitsLength": 32,
+ "nodeBitsLength": 16,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "behavior": "usid",
+ "statusUp": true,
+ "chunks": [
+ {
+ "prefix": "fc00:0:2::/48",
+ "proto": "system"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_locator_usid/expected_locators_6.json b/tests/topotests/srv6_locator_usid/expected_locators_6.json
new file mode 100644
index 000000000..b1528ff11
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/expected_locators_6.json
@@ -0,0 +1,35 @@
+{
+ "locators":[
+ {
+ "name": "loc1",
+ "prefix": "fc00:0:1::/48",
+ "blockBitsLength": 32,
+ "nodeBitsLength": 16,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "behavior": "usid",
+ "statusUp": true,
+ "chunks": [
+ {
+ "prefix": "fc00:0:1::/48",
+ "proto": "system"
+ }
+ ]
+ },
+ {
+ "name": "loc2",
+ "prefix": "fc00:0:2::/48",
+ "blockBitsLength": 32,
+ "nodeBitsLength": 16,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "statusUp": true,
+ "chunks": [
+ {
+ "prefix": "fc00:0:2::/48",
+ "proto": "system"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_locator_usid/expected_locators_7.json b/tests/topotests/srv6_locator_usid/expected_locators_7.json
new file mode 100644
index 000000000..e965e0217
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/expected_locators_7.json
@@ -0,0 +1,19 @@
+{
+ "locators":[
+ {
+ "name": "loc2",
+ "prefix": "fc00:0:2::/48",
+ "statusUp": true,
+ "blockBitsLength": 32,
+ "nodeBitsLength": 16,
+ "functionBitsLength": 16,
+ "argumentBitsLength": 0,
+ "chunks":[
+ {
+ "prefix": "fc00:0:2::/48",
+ "proto": "system"
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/srv6_locator_usid/expected_locators_8.json b/tests/topotests/srv6_locator_usid/expected_locators_8.json
new file mode 100644
index 000000000..6e1b993ca
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/expected_locators_8.json
@@ -0,0 +1,4 @@
+{
+ "locators":[
+ ]
+}
diff --git a/tests/topotests/srv6_locator_usid/r1/setup.sh b/tests/topotests/srv6_locator_usid/r1/setup.sh
new file mode 100644
index 000000000..36ed713f2
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/r1/setup.sh
@@ -0,0 +1,2 @@
+ip link add dummy0 type dummy
+ip link set dummy0 up
diff --git a/tests/topotests/srv6_locator_usid/r1/sharpd.conf b/tests/topotests/srv6_locator_usid/r1/sharpd.conf
new file mode 100644
index 000000000..d46085935
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/r1/sharpd.conf
@@ -0,0 +1,7 @@
+hostname r1
+!
+log stdout notifications
+log monitor notifications
+log commands
+log file sharpd.log debugging
+!
diff --git a/tests/topotests/srv6_locator_usid/r1/zebra.conf b/tests/topotests/srv6_locator_usid/r1/zebra.conf
new file mode 100644
index 000000000..78ef1e9d4
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/r1/zebra.conf
@@ -0,0 +1,20 @@
+hostname r1
+!
+! debug zebra events
+! debug zebra rib detailed
+!
+log stdout notifications
+log monitor notifications
+log commands
+log file zebra.log debugging
+!
+segment-routing
+ srv6
+ locators
+ locator loc1
+ prefix fc00:0:1::/48 func-bits 16 block-len 32 node-len 16
+ behavior usid
+ !
+ !
+ !
+!
diff --git a/tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py b/tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py
new file mode 100755
index 000000000..37fd736d2
--- /dev/null
+++ b/tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py
@@ -0,0 +1,276 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2022, University of Rome Tor Vergata
+# Authored by Carmine Scarpitta <carmine.scarpitta@uniroma2.it>
+#
+# 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_srv6_locator_usid.py:
+Test for SRv6 Locator uSID on zebra
+"""
+
+import os
+import sys
+import json
+import pytest
+import functools
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+pytestmark = [pytest.mark.bgpd, pytest.mark.sharpd]
+
+
+def open_json_file(filename):
+ try:
+ with open(filename, "r") as f:
+ return json.load(f)
+ except IOError:
+ assert False, "Could not read file {}".format(filename)
+
+
+def setup_module(mod):
+ tgen = Topogen({None: "r1"}, mod.__name__)
+ tgen.start_topology()
+ for rname, router in tgen.routers().items():
+ router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname))
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(
+ CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_SHARP, os.path.join(
+ CWD, "{}/sharpd.conf".format(rname))
+ )
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def _check_srv6_locator(router, expected_locator_file):
+ logger.info("checking zebra locator status")
+ output = json.loads(
+ router.vtysh_cmd("show segment-routing srv6 locator json")
+ )
+ expected = open_json_file("{}/{}".format(CWD, expected_locator_file))
+ return topotest.json_cmp(output, expected)
+
+
+def _check_sharpd_chunk(router, expected_chunk_file):
+ logger.info("checking sharpd locator chunk status")
+ output = json.loads(
+ router.vtysh_cmd("show sharp segment-routing srv6 json")
+ )
+ expected = open_json_file("{}/{}".format(CWD, expected_chunk_file))
+ return topotest.json_cmp(output, expected)
+
+
+def check_srv6_locator(router, expected_file):
+ func = functools.partial(_check_srv6_locator, router, expected_file)
+ success, result = topotest.run_and_expect(func, None, count=5, wait=3)
+ assert result is None, "Failed"
+
+
+def check_sharpd_chunk(router, expected_file):
+ func = functools.partial(_check_sharpd_chunk, router, expected_file)
+ success, result = topotest.run_and_expect(func, None, count=5, wait=3)
+ assert result is None, "Failed"
+
+
+def test_srv6_usid_locator_configuration():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ router = tgen.gears["r1"]
+
+ # FOR DEVELOPER:
+ # If you want to stop some specific line and start interactive shell,
+ # please use tgen.mininet_cli() to start it.
+
+ logger.info("Verify SRv6 Locators instantiated from config file")
+ check_srv6_locator(router, "expected_locators_1.json")
+ check_sharpd_chunk(router, "expected_chunks_1.json")
+
+
+def test_srv6_usid_locator_get_chunk():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ router = tgen.gears["r1"]
+
+ # FOR DEVELOPER:
+ # If you want to stop some specific line and start interactive shell,
+ # please use tgen.mininet_cli() to start it.
+
+ logger.info("Get chunk for the locator loc1")
+ router.vtysh_cmd("sharp srv6-manager get-locator-chunk loc1")
+ check_srv6_locator(router, "expected_locators_2.json")
+ check_sharpd_chunk(router, "expected_chunks_2.json")
+
+
+def test_srv6_usid_locator_release_chunk():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ router = tgen.gears["r1"]
+
+ # FOR DEVELOPER:
+ # If you want to stop some specific line and start interactive shell,
+ # please use tgen.mininet_cli() to start it.
+
+ logger.info("Release chunk for the locator loc1")
+ router.vtysh_cmd("sharp srv6-manager release-locator-chunk loc1")
+ check_srv6_locator(router, "expected_locators_3.json")
+ check_sharpd_chunk(router, "expected_chunks_3.json")
+
+
+def test_srv6_usid_locator_create_locator():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ router = tgen.gears["r1"]
+
+ # FOR DEVELOPER:
+ # If you want to stop some specific line and start interactive shell,
+ # please use tgen.mininet_cli() to start it.
+
+ logger.info("Create an additional SRv6 Locator")
+ router.vtysh_cmd(
+ """
+ configure terminal
+ segment-routing
+ srv6
+ locators
+ locator loc2
+ prefix fc00:0:2::/48 func-bits 16 block-len 32 node-len 16
+ """
+ )
+ check_srv6_locator(router, "expected_locators_4.json")
+ check_sharpd_chunk(router, "expected_chunks_4.json")
+
+
+def test_srv6_usid_locator_set_behavior_usid():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ router = tgen.gears["r1"]
+
+ # FOR DEVELOPER:
+ # If you want to stop some specific line and start interactive shell,
+ # please use tgen.mininet_cli() to start it.
+
+ logger.info(
+ "Specify the SRv6 Locator loc2 as a Micro-segment (uSID) Locator"
+ )
+ router.vtysh_cmd(
+ """
+ configure terminal
+ segment-routing
+ srv6
+ locators
+ locator loc2
+ behavior usid
+ """
+ )
+ check_srv6_locator(router, "expected_locators_5.json")
+ check_sharpd_chunk(router, "expected_chunks_5.json")
+
+
+def test_srv6_usid_locator_unset_behavior_usid():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ router = tgen.gears["r1"]
+
+ # FOR DEVELOPER:
+ # If you want to stop some specific line and start interactive shell,
+ # please use tgen.mininet_cli() to start it.
+
+ logger.info("Clear Micro-segment (uSID) Locator flag for loc2")
+ router.vtysh_cmd(
+ """
+ configure terminal
+ segment-routing
+ srv6
+ locators
+ locator loc2
+ no behavior usid
+ """
+ )
+ check_srv6_locator(router, "expected_locators_6.json")
+ check_sharpd_chunk(router, "expected_chunks_6.json")
+
+
+def test_srv6_usid_locator_delete():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ router = tgen.gears["r1"]
+
+ # FOR DEVELOPER:
+ # If you want to stop some specific line and start interactive shell,
+ # please use tgen.mininet_cli() to start it.
+
+ logger.info(
+ "Delete locator loc1 and verify that the chunk is released automatically"
+ )
+ router.vtysh_cmd(
+ """
+ configure terminal
+ segment-routing
+ srv6
+ locators
+ no locator loc1
+ """
+ )
+ check_srv6_locator(router, "expected_locators_7.json")
+ check_sharpd_chunk(router, "expected_chunks_7.json")
+
+
+def test_srv6_usid_locator_delete_all():
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ router = tgen.gears["r1"]
+
+ # FOR DEVELOPER:
+ # If you want to stop some specific line and start interactive shell,
+ # please use tgen.mininet_cli() to start it.
+
+ logger.info("Delete all the SRv6 configuration")
+ router.vtysh_cmd(
+ """
+ configure terminal
+ segment-routing
+ no srv6
+ """
+ )
+ check_srv6_locator(router, "expected_locators_8.json")
+ check_sharpd_chunk(router, "expected_chunks_8.json")
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/zebra_seg6local_route/r1/routes.json b/tests/topotests/zebra_seg6local_route/r1/routes.json
index 4cb1c4ae1..e39192256 100644
--- a/tests/topotests/zebra_seg6local_route/r1/routes.json
+++ b/tests/topotests/zebra_seg6local_route/r1/routes.json
@@ -94,5 +94,30 @@
"seg6local": { "action": "End.DX4" }
}]
}]
+ },
+ {
+ "in": {
+ "dest": "5::1",
+ "context": "End_DT46 10"
+ },
+ "out":[{
+ "prefix":"5::1/128",
+ "protocol":"sharp",
+ "selected":true,
+ "destSelected":true,
+ "distance":150,
+ "metric":0,
+ "installed":true,
+ "table":254,
+ "nexthops":[{
+ "flags":3,
+ "fib":true,
+ "active":true,
+ "directlyConnected":true,
+ "interfaceName": "dum0",
+ "seg6local": { "action": "End.DT46" }
+ }]
+ }],
+ "required_kernel": "5.14"
}
]
diff --git a/tests/topotests/zebra_seg6local_route/r1/setup.sh b/tests/topotests/zebra_seg6local_route/r1/setup.sh
index 691adb0a1..ec27ec95b 100644
--- a/tests/topotests/zebra_seg6local_route/r1/setup.sh
+++ b/tests/topotests/zebra_seg6local_route/r1/setup.sh
@@ -1,3 +1,6 @@
ip link add dum0 type dummy
ip link set dum0 up
+ip link add vrf10 type vrf table 10
+ip link set vrf10 up
sysctl -w net.ipv6.conf.dum0.disable_ipv6=0
+sysctl -w net.vrf.strict_mode=1
diff --git a/tests/topotests/zebra_seg6local_route/test_zebra_seg6local_route.py b/tests/topotests/zebra_seg6local_route/test_zebra_seg6local_route.py
index d9cca5cd9..66d3b6d91 100755
--- a/tests/topotests/zebra_seg6local_route/test_zebra_seg6local_route.py
+++ b/tests/topotests/zebra_seg6local_route/test_zebra_seg6local_route.py
@@ -38,6 +38,7 @@ sys.path.append(os.path.join(CWD, "../"))
from lib import topotest
from lib.topogen import Topogen, TopoRouter, get_topogen
from lib.topolog import logger
+from lib.common_config import required_linux_kernel_version
pytestmark = [pytest.mark.sharpd]
@@ -93,6 +94,15 @@ def test_zebra_seg6local_routes():
logger.info("CHECK {} {}".format(dest, context))
+ if manifest.get("required_kernel") is not None:
+ if required_linux_kernel_version(manifest["required_kernel"]) is not True:
+ logger.info(
+ "Kernel requirements are not met. Skipping {} {}".format(
+ dest, context
+ )
+ )
+ continue
+
r1.vtysh_cmd(
"sharp install seg6local-routes {} nexthop-seg6local dum0 {} 1".format(
dest, context
diff --git a/tools/etc/frr/support_bundle_commands.conf b/tools/etc/frr/support_bundle_commands.conf
index ff2c633cc..914363157 100644
--- a/tools/etc/frr/support_bundle_commands.conf
+++ b/tools/etc/frr/support_bundle_commands.conf
@@ -208,3 +208,34 @@ show ipv6 ospf6 vrf all spf tree
show ipv6 ospf6 vrf all summary-address detail
show ipv6 ospf6 zebra
CMD_LIST_END
+
+#PIMv6 Support Bundle Command List
+PROC_NAME:pim6
+CMD_LIST_START
+show ipv6 pim channel
+show ipv6 pim interface
+show ipv6 pim interface traffic
+show ipv6 pim join
+show ipv6 jp-agg
+show ipv6 pim nexthop
+show ipv6 pim nexthop-lookup
+show ipv6 pim neighbor
+show ipv6 pim local-membership
+show ipv6 pim rp-info
+show ipv6 pim rpf
+show ipv6 pim secondary
+show ipv6 pim state
+show ipv6 pim statistics
+show ipv6 pim upstream
+show ipv6 pim upstream-join-desired
+show ipv6 pim upstream-rpf
+show ipv6 mld interface
+show ipv6 mld statistics
+show ipv6 mld joins
+show ipv6 mld groups
+show ipv6 multicast
+show ipv6 mroute
+show ipv6 pim bsr
+show ipv6 pim bsrp-info
+show ipv6 pim bsm-databases
+CMD_LIST_END
diff --git a/debian/frr.logrotate b/tools/etc/logrotate.d/frr
index 735af6539..735af6539 100644
--- a/debian/frr.logrotate
+++ b/tools/etc/logrotate.d/frr
diff --git a/tools/frr-reload.py b/tools/frr-reload.py
index 32f9a7884..7c5d91d4d 100755
--- a/tools/frr-reload.py
+++ b/tools/frr-reload.py
@@ -890,7 +890,7 @@ def bgp_remove_neighbor_cfg(lines_to_del, del_nbr_dict):
):
if ctx_keys[0] in del_nbr_dict:
for nbr in del_nbr_dict[ctx_keys[0]]:
- re_nbr_pg = re.search('neighbor (\S+) .*peer-group (\S+)', line)
+ re_nbr_pg = re.search("neighbor (\S+) .*peer-group (\S+)", line)
nb_exp = "neighbor %s .*" % nbr
if not re_nbr_pg:
re_nb = re.search(nb_exp, line)
@@ -997,7 +997,7 @@ def delete_move_lines(lines_to_add, lines_to_del):
# 'no neighbor peer [interface] peer-group <>' is in lines_to_del
# copy the neighbor and look for all config removal lines associated
# to neighbor and delete them from the lines_to_del
- re_nbr_pg = re.search('neighbor (\S+) .*peer-group (\S+)', line)
+ re_nbr_pg = re.search("neighbor (\S+) .*peer-group (\S+)", line)
if re_nbr_pg:
if ctx_keys[0] not in del_nbr_dict:
del_nbr_dict[ctx_keys[0]] = list()
@@ -1376,6 +1376,37 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del):
lines_to_add.append((add_cmd, None))
lines_to_del_to_del.append((ctx_keys, None))
+ # bgp community-list, large-community-list, extcommunity-list can be
+ # specified without a seq number. However, the running config always
+ # adds `seq X` (sequence number). So, ignore such lines as well.
+ # Examples:
+ # bgp community-list standard clist seq 5 permit 222:213
+ # bgp large-community-list standard llist seq 5 permit 65001:65001:1
+ # bgp extcommunity-list standard elist seq 5 permit soo 123:123
+ re_bgp_lists = re.search(
+ "^(bgp )(community-list|large-community-list|extcommunity-list)(\s+\S+\s+)(\S+\s+)(seq \d+\s+)(permit|deny)(.*)$",
+ ctx_keys[0],
+ )
+ if re_bgp_lists:
+ found = False
+ tmpline = (
+ re_bgp_lists.group(1)
+ + re_bgp_lists.group(2)
+ + re_bgp_lists.group(3)
+ + re_bgp_lists.group(4)
+ + re_bgp_lists.group(6)
+ + re_bgp_lists.group(7)
+ )
+ for ctx in lines_to_add:
+ if ctx[0][0] == tmpline:
+ lines_to_del_to_del.append((ctx_keys, None))
+ lines_to_add_to_del.append(((tmpline,), None))
+ found = True
+ if found is False:
+ add_cmd = ("no " + ctx_keys[0],)
+ lines_to_add.append((add_cmd, None))
+ lines_to_del_to_del.append((ctx_keys, None))
+
if (
len(ctx_keys) == 3
and ctx_keys[0].startswith("router bgp")
diff --git a/tools/frr.in b/tools/frr.in
index 27b2c0ab8..1ffdade54 100755
--- a/tools/frr.in
+++ b/tools/frr.in
@@ -53,13 +53,6 @@ vtyfile()
echo "$V_PATH/$1.vty"
}
-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.
started()
{
@@ -103,12 +96,10 @@ check_daemon()
# check for config file
if [ -n "$2" ]; then
if [ ! -r "$C_PATH/$1-$2.conf" ]; then
- touch "$C_PATH/$1-$2.conf"
- chownfrr "$C_PATH/$1-$2.conf"
+ install -g "$FRR_GROUP" -o "$FRR_USER" -m "$FRR_CONFIG_MODE" /dev/null "$C_PATH/$1-$2.conf"
fi
elif [ ! -r "$C_PATH/$1.conf" ]; then
- touch "$C_PATH/$1.conf"
- chownfrr "$C_PATH/$1.conf"
+ install -g "$FRR_GROUP" -o "$FRR_USER" -m "$FRR_CONFIG_MODE" /dev/null "$C_PATH/$1.conf"
fi
fi
return 0
@@ -533,9 +524,8 @@ convert_daemon_prios
if [ ! -d $V_PATH ]; then
echo "Creating $V_PATH"
- mkdir -p $V_PATH
- chownfrr $V_PATH
- chmod 755 /$V_PATH
+ install -g "$FRR_GROUP" -o "$FRR_USER" -m "$FRR_CONFIG_MODE" -d "$V_PATH"
+ chmod gu+x "${V_PATH}"
fi
if [ -n "$3" ] && [ "$3" != "all" ]; then
@@ -592,7 +582,7 @@ case "$1" in
NEW_CONFIG_FILE="${2:-$C_PATH/frr.conf}"
[ ! -r $NEW_CONFIG_FILE ] && echo "Unable to read new configuration file $NEW_CONFIG_FILE" && exit 1
echo "Applying only incremental changes to running configuration from frr.conf"
- "$RELOAD_SCRIPT" --reload $C_PATH/frr.conf
+ "$RELOAD_SCRIPT" --reload --bindir "$D_PATH" --confdir "$C_PATH" --rundir "$V_PATH" "$C_PATH/frr.conf"
exit $?
;;
diff --git a/tools/frrcommon.sh.in b/tools/frrcommon.sh.in
index b589ced96..3c16c27c6 100755
--- a/tools/frrcommon.sh.in
+++ b/tools/frrcommon.sh.in
@@ -62,15 +62,6 @@ debug() {
printf '\n' >&2
}
-chownfrr() {
- [ -n "$FRR_USER" ] && chown "$FRR_USER" "$1"
- [ -n "$FRR_GROUP" ] && chgrp "$FRR_GROUP" "$1"
- [ -n "$FRR_CONFIG_MODE" ] && chmod "$FRR_CONFIG_MODE" "$1"
- if [ -d "$1" ]; then
- chmod gu+x "$1"
- fi
-}
-
vtysh_b () {
[ "$1" = "watchfrr" ] && return 0
if [ ! -r "$C_PATH/frr.conf" ]; then
@@ -152,8 +143,7 @@ daemon_prep() {
cfg="$C_PATH/$daemon${inst:+-$inst}.conf"
if [ ! -r "$cfg" ]; then
- touch "$cfg"
- chownfrr "$cfg"
+ install -g "$FRR_GROUP" -o "$FRR_USER" -m "$FRR_CONFIG_MODE" /dev/null "$cfg"
fi
return 0
}
@@ -171,8 +161,8 @@ daemon_start() {
[ "$MAX_FDS" != "" ] && ulimit -n "$MAX_FDS" > /dev/null 2> /dev/null
daemon_prep "$daemon" "$inst" || return 1
if test ! -d "$V_PATH"; then
- mkdir -p "$V_PATH"
- chownfrr "$V_PATH"
+ install -g "$FRR_GROUP" -o "$FRR_USER" -m "$FRR_CONFIG_MODE" -d "$V_PATH"
+ chmod gu+x "${V_PATH}"
fi
eval wrap="\$${daemon}_wrap"
@@ -345,7 +335,7 @@ if [ -z "$FRR_PATHSPACE" ]; then
load_old_config "/etc/sysconfig/frr"
fi
-if { declare -p watchfrr_options 2>/dev/null || true; } | grep -q '^declare \-a'; then
+if { declare -p watchfrr_options 2>/dev/null || true; } | grep -q '^declare -a'; then
log_warning_msg "watchfrr_options contains a bash array value." \
"The configured value is intentionally ignored since it is likely wrong." \
"Please remove or fix the setting."
diff --git a/tools/frrinit.sh.in b/tools/frrinit.sh.in
index ee10b89e5..2396b1a32 100644
--- a/tools/frrinit.sh.in
+++ b/tools/frrinit.sh.in
@@ -122,7 +122,7 @@ reload)
NEW_CONFIG_FILE="${2:-$C_PATH/frr.conf}"
[ ! -r $NEW_CONFIG_FILE ] && log_failure_msg "Unable to read new configuration file $NEW_CONFIG_FILE" && exit 1
- "$RELOAD_SCRIPT" --reload "$NEW_CONFIG_FILE" `echo $nsopt`
+ "$RELOAD_SCRIPT" --reload --bindir "$D_PATH" --confdir "$C_PATH" --rundir "$V_PATH" "$NEW_CONFIG_FILE" `echo $nsopt`
exit $?
;;
diff --git a/tools/permutations.c b/tools/permutations.c
index b280cc15b..a0b041f2f 100644
--- a/tools/permutations.c
+++ b/tools/permutations.c
@@ -80,8 +80,7 @@ void permute(struct graph_node *start)
for (unsigned int i = 0; i < vector_active(start->to); i++) {
struct graph_node *gn = vector_slot(start->to, i);
struct cmd_token *tok = gn->data;
- if (tok->attr == CMD_ATTR_HIDDEN
- || tok->attr == CMD_ATTR_DEPRECATED)
+ if (tok->attr & CMD_ATTR_HIDDEN)
continue;
else if (tok->type == END_TKN || gn == start) {
fprintf(stdout, " ");
diff --git a/vrrpd/subdir.am b/vrrpd/subdir.am
index 02e0497ee..03b404261 100644
--- a/vrrpd/subdir.am
+++ b/vrrpd/subdir.am
@@ -4,7 +4,6 @@
if VRRPD
sbin_PROGRAMS += vrrpd/vrrpd
-vtysh_scan += vrrpd/vrrp_vty.c
vtysh_daemons += vrrpd
man8 += $(MANBUILD)/frr-vrrpd.8
endif
diff --git a/vrrpd/vrrp_vty.c b/vrrpd/vrrp_vty.c
index 634a55dbc..f822b8985 100644
--- a/vrrpd/vrrp_vty.c
+++ b/vrrpd/vrrp_vty.c
@@ -33,9 +33,7 @@
#include "vrrp_debug.h"
#include "vrrp_vty.h"
#include "vrrp_zebra.h"
-#ifndef VTYSH_EXTRACT_PL
#include "vrrpd/vrrp_vty_clippy.c"
-#endif
#define VRRP_STR "Virtual Router Redundancy Protocol\n"
@@ -121,7 +119,7 @@ DEFPY_YANG(vrrp_priority,
VRRP_STR
VRRP_VRID_STR
VRRP_PRIORITY_STR
- "Priority value")
+ "Priority value\n")
{
nb_cli_enqueue_change(vty, "./priority", NB_OP_MODIFY, priority_str);
@@ -138,7 +136,7 @@ DEFPY_YANG(no_vrrp_priority,
VRRP_STR
VRRP_VRID_STR
VRRP_PRIORITY_STR
- "Priority value")
+ "Priority value\n")
{
nb_cli_enqueue_change(vty, "./priority", NB_OP_MODIFY, NULL);
@@ -162,7 +160,7 @@ DEFPY_YANG(vrrp_advertisement_interval,
vrrp_advertisement_interval_cmd,
"vrrp (1-255)$vrid advertisement-interval (10-40950)",
VRRP_STR VRRP_VRID_STR VRRP_ADVINT_STR
- "Advertisement interval in milliseconds; must be multiple of 10")
+ "Advertisement interval in milliseconds; must be multiple of 10\n")
{
char val[20];
@@ -183,7 +181,7 @@ DEFPY_YANG(no_vrrp_advertisement_interval,
no_vrrp_advertisement_interval_cmd,
"no vrrp (1-255)$vrid advertisement-interval [(10-40950)]",
NO_STR VRRP_STR VRRP_VRID_STR VRRP_ADVINT_STR
- "Advertisement interval in milliseconds; must be multiple of 10")
+ "Advertisement interval in milliseconds; must be multiple of 10\n")
{
nb_cli_enqueue_change(vty, "./advertisement-interval", NB_OP_MODIFY,
NULL);
@@ -710,6 +708,8 @@ DEFUN_NOSH (show_debugging_vrrp,
vrrp_debug_status_write(vty);
+ cmd_show_lib_debugs(vty);
+
return CMD_SUCCESS;
}
diff --git a/vtysh/.gitignore b/vtysh/.gitignore
index 118b84407..09e90e51d 100644
--- a/vtysh/.gitignore
+++ b/vtysh/.gitignore
@@ -1,4 +1,6 @@
vtysh
vtysh_cmd.c
-extract.pl
vtysh_daemons.h
+
+# does not exist anymore - remove 2023-10-04 or so
+extract.pl
diff --git a/vtysh/extract.pl.in b/vtysh/extract.pl.in
deleted file mode 100755
index 228a136b7..000000000
--- a/vtysh/extract.pl.in
+++ /dev/null
@@ -1,282 +0,0 @@
-#! @PERL@
-##
-## @configure_input@
-##
-## Virtual terminal interface shell command extractor.
-## Copyright (C) 2000 Kunihiro Ishiguro
-##
-## This file is part of GNU Zebra.
-##
-## GNU Zebra is free software; you can redistribute it and/or modify it
-## under the terms of the GNU General Public License as published by the
-## Free Software Foundation; either version 2, or (at your option) any
-## later version.
-##
-## GNU Zebra is distributed in the hope that it will be useful, but
-## WITHOUT ANY WARRANTY; without even the implied warranty of
-## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-## General Public License for more details.
-##
-## You should have received a copy of the GNU General Public License
-## along with GNU Zebra; see the file COPYING. If not, write to the Free
-## Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
-## 02111-1307, USA.
-##
-
-use Getopt::Long;
-
-print <<EOF;
-#include <zebra.h>
-
-#include "command.h"
-#include "linklist.h"
-
-#include "vtysh/vtysh.h"
-
-EOF
-
-my $cli_stomp = 0;
-
-sub scan_file {
- my ( $file, $fabricd) = @_;
-
- $cppadd = $fabricd ? "-DFABRICD=1" : "";
-
- $command_line = "@CPP@ -P -std=gnu11 -DHAVE_CONFIG_H -DVTYSH_EXTRACT_PL -Ivtysh/@top_builddir@ -Ivtysh/@top_srcdir@ -Ivtysh/@top_srcdir@/lib -Ivtysh/@top_builddir@/lib -Ivtysh/@top_srcdir@/bgpd -Ivtysh/@top_srcdir@/bgpd/rfapi @LUA_INCLUDE@ @CPPFLAGS@ @LIBYANG_CFLAGS@ $cppadd $file |";
- open (FH, $command_line)
- || die "Open to the pipeline failed: $!\n\nCommand Issued:\n$command_line";
- local $/; undef $/;
- $line = <FH>;
- if (!close (FH)) {
- die "File: $file failed to compile:\n$!\nwhen extracting cli from it please inspect\n"
- }
-
- # ?: makes a group non-capturing
- @defun = ($line =~ /((?:DEFUN|DEFUN_HIDDEN|DEFUN_YANG|ALIAS|ALIAS_HIDDEN|ALIAS_YANG|DEFPY|DEFPY_HIDDEN|DEFPY_YANG)\s*\(.+?\));?\s?\s?\n/sg);
- @install = ($line =~ /install_element\s*\(\s*[0-9A-Z_]+,\s*&[^;]*;\s*\n/sg);
-
- # DEFUN process
- foreach (@defun) {
- # $_ will contain the entire string including the DEFUN, ALIAS, etc.
- # We need to extract the DEFUN/ALIAS from everything in ()s.
- # The /s at the end tells the regex to allow . to match newlines.
- $_ =~ /^(.*?)\s*\((.*)\)$/s;
-
- my (@defun_array);
- $defun_or_alias = $1;
- @defun_array = split (/,/, $2);
-
- if ($defun_or_alias =~ /_HIDDEN/) {
- $hidden = 1;
- } else {
- $hidden = 0;
- }
-
- $defun_array[0] = '';
-
- # Actual input command string.
- $str = "$defun_array[2]";
- $str =~ s/^\s+//g;
- $str =~ s/\s+$//g;
-
- # Get VTY command structure. This is needed for searching
- # install_element() command.
- $cmd = "$defun_array[1]";
- $cmd =~ s/^\s+//g;
- $cmd =~ s/\s+$//g;
-
- if ($fabricd) {
- $cmd = "fabricd_" . $cmd;
- }
-
- # $protocol is VTYSH_PROTO format for redirection of user input
- if ($file =~ /lib\/keychain\.c$/) {
- $protocol = "VTYSH_RIPD|VTYSH_EIGRPD|VTYSH_OSPF6D";
- }
- elsif ($file =~ /lib\/routemap\.c$/ || $file =~ /lib\/routemap_cli\.c$/) {
- $protocol = "VTYSH_RMAP";
- }
- elsif ($file =~ /lib\/vrf\.c$/) {
- $protocol = "VTYSH_VRF";
- }
- elsif ($file =~ /lib\/if\.c$/) {
- $protocol = "VTYSH_INTERFACE";
- }
- elsif ($file =~ /lib\/(filter|filter_cli)\.c$/) {
- $protocol = "VTYSH_ACL";
- }
- elsif ($file =~ /lib\/(lib|log)_vty\.c$/) {
- $protocol = "VTYSH_ALL";
- }
- elsif ($file =~ /lib\/agentx\.c$/) {
- $protocol = "VTYSH_ISISD|VTYSH_RIPD|VTYSH_OSPFD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA";
- }
- elsif ($file =~ /lib\/nexthop_group\.c$/) {
- $protocol = "VTYSH_NH_GROUP";
- }
- elsif ($file =~ /lib\/plist\.c$/) {
- if ($defun_array[1] =~ m/ipv6/) {
- $protocol = "VTYSH_RIPNGD|VTYSH_OSPF6D|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_PIM6D|VTYSH_BABELD|VTYSH_ISISD|VTYSH_FABRICD";
- } else {
- $protocol = "VTYSH_RIPD|VTYSH_OSPFD|VTYSH_BGPD|VTYSH_ZEBRA|VTYSH_PIMD|VTYSH_EIGRPD|VTYSH_BABELD|VTYSH_ISISD|VTYSH_FABRICD";
- }
- }
- elsif ($file =~ /lib\/if_rmap\.c$/) {
- if ($defun_array[1] =~ m/ipv6/) {
- $protocol = "VTYSH_RIPNGD";
- } else {
- $protocol = "VTYSH_RIPD";
- }
- }
- elsif ($file =~ /lib\/resolver\.c$/) {
- $protocol = "VTYSH_NHRPD|VTYSH_BGPD";
- }
- elsif ($file =~ /lib\/spf_backoff\.c$/) {
- $protocol = "VTYSH_ISISD";
- }
- elsif ($file =~ /lib\/(vty|thread)\.c$/) {
- $protocol = "VTYSH_ALL";
- }
- elsif ($file =~ /librfp\/.*\.c$/ || $file =~ /rfapi\/.*\.c$/) {
- $protocol = "VTYSH_BGPD";
- }
- elsif ($fabricd) {
- $protocol = "VTYSH_FABRICD";
- }
- elsif ($file =~ /pimd\/pim6_.*\.c$/) {
- $protocol = "VTYSH_PIM6D";
- }
- else {
- ($protocol) = ($file =~ /^(?:.*\/)?([a-z0-9]+)\/[a-zA-Z0-9_\-]+\.c$/);
- $protocol = "VTYSH_" . uc $protocol;
- }
-
- # Append _vtysh to structure then build DEFUN again
- $defun_array[1] = $cmd . "_vtysh";
- $defun_body = join (", ", @defun_array);
-
- # $cmd -> $str hash for lookup
- if (exists($cmd2str{$cmd})) {
- warn "Duplicate CLI Function: $cmd\n";
- warn "\tFrom cli: $cmd2str{$cmd} to New cli: $str\n";
- warn "\tOriginal Protocol: $cmd2proto{$cmd} to New Protocol: $protocol\n";
- $cli_stomp++;
- }
- $cmd2str{$cmd} = $str;
- $cmd2defun{$cmd} = $defun_body;
- $cmd2proto{$cmd} = $protocol;
- $cmd2hidden{$cmd} = $hidden;
- }
-
- # install_element() process
- foreach (@install) {
- my (@element_array);
- @element_array = split (/,/);
-
- # Install node
- $enode = $element_array[0];
- $enode =~ s/^\s+//g;
- $enode =~ s/\s+$//g;
- ($enode) = ($enode =~ /([0-9A-Z_]+)$/);
-
- # VTY command structure.
- ($ecmd) = ($element_array[1] =~ /&([^\)]+)/);
- $ecmd =~ s/^\s+//g;
- $ecmd =~ s/\s+$//g;
-
- if ($fabricd) {
- $ecmd = "fabricd_" . $ecmd;
- }
-
- # Register $ecmd
- if (defined ($cmd2str{$ecmd})) {
- my ($key);
- $key = $enode . "," . $cmd2str{$ecmd};
- $ocmd{$key} = $ecmd;
- $odefun{$key} = $cmd2defun{$ecmd};
-
- if ($cmd2hidden{$ecmd}) {
- $defsh{$key} = "DEFSH_HIDDEN"
- } else {
- $defsh{$key} = "DEFSH"
- }
- push (@{$oproto{$key}}, $cmd2proto{$ecmd});
- }
- }
-}
-
-my $have_isisd = 0;
-my $have_fabricd = 0;
-
-GetOptions('have-isisd' => \$have_isisd, 'have-fabricd' => \$have_fabricd);
-
-foreach (@ARGV) {
- if (/(^|\/)isisd\//) {
- # We scan all the IS-IS files twice, once for isisd,
- # once for fabricd. Exceptions are made for the files
- # that are not shared between the two.
- if (/isis_vty_isisd.c/) {
- if ( $have_isisd ) {
- scan_file($_, 0);
- }
- } elsif (/isis_vty_fabricd.c/) {
- if ( $have_fabricd ) {
- scan_file($_, 1);
- }
- } else {
- if ( $have_isisd ) {
- scan_file($_, 0);
- }
- if ( $have_fabricd ) {
- scan_file($_, 1);
- }
- }
- } else {
- scan_file($_, 0);
- }
-}
-
-# When we have cli commands that map to the same function name, we
-# can introduce subtle bugs due to code not being called when
-# we think it is.
-#
-# If extract.pl fails with a error message and you've been
-# modifying the cli, then go back and fix your code to
-# not have cli command function collisions.
-# please fix your code before submittal
-if ($cli_stomp) {
- warn "There are $cli_stomp command line stomps\n";
-}
-
-# Check finaly alive $cmd;
-foreach (keys %odefun) {
- my ($node, $str) = (split (/,/));
- my ($cmd) = $ocmd{$_};
- $live{$cmd} = $_;
-}
-
-# Output DEFSH
-foreach (sort keys %live) {
- my ($proto);
- my ($key);
- $key = $live{$_};
- $proto = join ("|", @{$oproto{$key}});
- printf "$defsh{$key} ($proto$odefun{$key})\n\n";
-}
-
-# Output install_element
-print <<EOF;
-void vtysh_init_cmd(void)
-{
-EOF
-
-foreach (sort keys %odefun) {
- my ($node, $str) = (split (/,/));
- $cmd = $ocmd{$_};
- $cmd =~ s/_cmd$/_cmd_vtysh/;
- printf " install_element ($node, &$cmd);\n";
-}
-
-print <<EOF
-}
-EOF
diff --git a/vtysh/subdir.am b/vtysh/subdir.am
index 624361645..cc2a70ade 100644
--- a/vtysh/subdir.am
+++ b/vtysh/subdir.am
@@ -20,7 +20,6 @@ vtysh_vtysh_SOURCES = \
nodist_vtysh_vtysh_SOURCES = \
vtysh/vtysh_cmd.c \
# end
-CLEANFILES += vtysh/vtysh_cmd.c
noinst_HEADERS += \
vtysh/vtysh.h \
@@ -39,23 +38,3 @@ $(vtysh_vtysh_OBJECTS): vtysh/vtysh_daemons.h
CLEANFILES += vtysh/vtysh_daemons.h
vtysh/vtysh_daemons.h:
$(PERL) $(top_srcdir)/vtysh/daemons.pl $(vtysh_daemons) > vtysh/vtysh_daemons.h
-
-AM_V_EXTRACT = $(am__v_EXTRACT_$(V))
-am__v_EXTRACT_ = $(am__v_EXTRACT_$(AM_DEFAULT_VERBOSITY))
-am__v_EXTRACT_0 = @echo " EXTRACT " $@;
-am__v_EXTRACT_1 =
-
-if ISISD
-HAVE_ISISD = --have-isisd
-else
-HAVE_ISISD =
-endif
-
-if FABRICD
-HAVE_FABRICD = --have-fabricd
-else
-HAVE_FABRICD =
-endif
-
-vtysh/vtysh_cmd.c: vtysh/extract.pl $(vtysh_scan)
- $(AM_V_EXTRACT) $^ $(HAVE_ISISD) $(HAVE_FABRICD) > vtysh/vtysh_cmd.c
diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c
index f39ecf070..48274d717 100644
--- a/vtysh/vtysh.c
+++ b/vtysh/vtysh.c
@@ -2951,7 +2951,7 @@ DEFUN_HIDDEN (show_config_running,
show_config_running_cmd,
"show configuration running\
[<json|xml> [translate WORD]]\
- [with-defaults]" DAEMONS_LIST,
+ [with-defaults] " DAEMONS_LIST,
SHOW_STR
"Configuration information\n"
"Running configuration\n"
@@ -2972,7 +2972,7 @@ DEFUN (show_yang_operational_data,
format <json|xml>\
|translate WORD\
|with-config\
- }]" DAEMONS_LIST,
+ }] " DAEMONS_LIST,
SHOW_STR
"YANG information\n"
"Show YANG operational data\n"
diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c
index d98f83dbf..ac0cdc6ff 100644
--- a/vtysh/vtysh_config.c
+++ b/vtysh/vtysh_config.c
@@ -261,6 +261,11 @@ static void config_add_line_uniq_end(struct list *config, const char *line)
listnode_move_to_tail(config, node);
}
+static void config_add_line_head(struct list *config, const char *line)
+{
+ listnode_add_head(config, XSTRDUP(MTYPE_VTYSH_CONFIG_LINE, line));
+}
+
void vtysh_config_parse_line(void *arg, const char *line)
{
char c;
@@ -324,12 +329,19 @@ void vtysh_config_parse_line(void *arg, const char *line)
} else if (!strncmp(line, " ip mroute",
strlen(" ip mroute"))) {
config_add_line_uniq_end(config->line, line);
- } else if (config->index == RMAP_NODE
- || config->index == INTERFACE_NODE
- || config->index == VTY_NODE
- || config->index == NH_GROUP_NODE)
+ } else if (config->index == RMAP_NODE ||
+ config->index == INTERFACE_NODE ||
+ config->index == VTY_NODE)
config_add_line_uniq(config->line, line);
- else
+ else if (config->index == NH_GROUP_NODE) {
+ if (strncmp(line, " resilient",
+ strlen(" resilient")) == 0)
+ config_add_line_head(config->line,
+ line);
+ else
+ config_add_line_uniq_end(config->line,
+ line);
+ } else
config_add_line(config->line, line);
} else
config_add_line(config_top, line);
@@ -492,8 +504,8 @@ void vtysh_config_parse_line(void *arg, const char *line)
strlen("no ip prefix-list")) == 0 ||
strncmp(line, "no ipv6 prefix-list",
strlen("no ipv6 prefix-list")) == 0 ||
- strncmp(line, "service cputime-stats",
- strlen("service cputime-stats")) == 0 ||
+ strncmp(line, "service ", strlen("service ")) ==
+ 0 ||
strncmp(line, "no service cputime-stats",
strlen("no service cputime-stats")) == 0 ||
strncmp(line, "service cputime-warning",
@@ -652,18 +664,21 @@ int vtysh_read_config(const char *config_default_dir, bool dry_run)
*/
void vtysh_config_write(void)
{
+ const char *name;
char line[512];
- if (cmd_hostname_get()) {
- snprintf(line, sizeof(line), "hostname %s", cmd_hostname_get());
+ name = cmd_hostname_get();
+ if (name && name[0] != '\0') {
+ snprintf(line, sizeof(line), "hostname %s", name);
vtysh_config_parse_line(NULL, line);
}
- if (cmd_domainname_get()) {
- snprintf(line, sizeof(line), "domainname %s",
- cmd_domainname_get());
+ name = cmd_domainname_get();
+ if (name && name[0] != '\0') {
+ snprintf(line, sizeof(line), "domainname %s", name);
vtysh_config_parse_line(NULL, line);
}
+
if (vtysh_write_integrated == WRITE_INTEGRATED_NO)
vtysh_config_parse_line(NULL,
"no service integrated-vtysh-config");
diff --git a/watchfrr/subdir.am b/watchfrr/subdir.am
index e899b895e..04a4aaf16 100644
--- a/watchfrr/subdir.am
+++ b/watchfrr/subdir.am
@@ -4,7 +4,6 @@
if WATCHFRR
sbin_PROGRAMS += watchfrr/watchfrr
-vtysh_scan += watchfrr/watchfrr_vty.c
man8 += $(MANBUILD)/frr-watchfrr.8
endif
diff --git a/watchfrr/watchfrr.c b/watchfrr/watchfrr.c
index 423f25faa..4a3575ae7 100644
--- a/watchfrr/watchfrr.c
+++ b/watchfrr/watchfrr.c
@@ -112,6 +112,7 @@ static struct global_state {
long period;
long timeout;
long restart_timeout;
+ bool reading_configuration;
long min_restart_interval;
long max_restart_interval;
long operational_timeout;
@@ -365,6 +366,16 @@ static void restart_kill(struct thread *t_kill)
struct timeval delay;
time_elapsed(&delay, &restart->time);
+
+ if (gs.reading_configuration) {
+ zlog_err(
+ "%s %s child process appears to still be reading configuration, delaying for another %lu time",
+ restart->what, restart->name, gs.restart_timeout);
+ thread_add_timer(master, restart_kill, restart,
+ gs.restart_timeout, &restart->t_kill);
+ return;
+ }
+
zlog_warn(
"%s %s child process %d still running after %ld seconds, sending signal %d",
restart->what, restart->name, (int)restart->pid,
@@ -1059,6 +1070,8 @@ void watchfrr_status(struct vty *vty)
vty_out(vty, " Min Restart Interval: %ld\n", gs.min_restart_interval);
vty_out(vty, " Max Restart Interval: %ld\n", gs.max_restart_interval);
vty_out(vty, " Restart Timeout: %ld\n", gs.restart_timeout);
+ vty_out(vty, " Reading Configuration: %s\n",
+ gs.reading_configuration ? "yes" : "no");
if (gs.restart.pid)
vty_out(vty, " global restart running, pid %ld\n",
(long)gs.restart.pid);
@@ -1264,6 +1277,16 @@ static void netns_setup(const char *nsname)
}
#endif
+static void watchfrr_start_config(void)
+{
+ gs.reading_configuration = true;
+}
+
+static void watchfrr_end_config(void)
+{
+ gs.reading_configuration = false;
+}
+
static void watchfrr_init(int argc, char **argv)
{
const char *special = "zebra";
@@ -1558,6 +1581,7 @@ int main(int argc, char **argv)
master = frr_init();
watchfrr_error_init();
watchfrr_init(argc, argv);
+ cmd_init_config_callbacks(watchfrr_start_config, watchfrr_end_config);
watchfrr_vty_init();
frr_config_fork();
diff --git a/watchfrr/watchfrr_vty.c b/watchfrr/watchfrr_vty.c
index 1492ee37b..742b474ea 100644
--- a/watchfrr/watchfrr_vty.c
+++ b/watchfrr/watchfrr_vty.c
@@ -125,6 +125,8 @@ DEFUN_NOSH (show_debugging_watchfrr,
DEBUG_STR
WATCHFRR_STR)
{
+ cmd_show_lib_debugs(vty);
+
return CMD_SUCCESS;
}
@@ -151,9 +153,7 @@ DEFUN_NOSH (show_logging,
return CMD_SUCCESS;
}
-#ifndef VTYSH_EXTRACT_PL
#include "watchfrr/watchfrr_vty_clippy.c"
-#endif
DEFPY (watchfrr_ignore_daemon,
watchfrr_ignore_daemon_cmd,
diff --git a/yang/frr-bgp-route-map.yang b/yang/frr-bgp-route-map.yang
index 3f3d82921..ad2a142fe 100644
--- a/yang/frr-bgp-route-map.yang
+++ b/yang/frr-bgp-route-map.yang
@@ -276,6 +276,12 @@ module frr-bgp-route-map {
"Set BGP atomic-aggregate attribute";
}
+ identity aigp-metric {
+ base frr-route-map:rmap-set-type;
+ description
+ "Set BGP AIGP attribute (AIGP TLV Metric)";
+ }
+
identity as-path-prepend {
base frr-route-map:rmap-set-type;
description
@@ -800,6 +806,15 @@ module frr-bgp-route-map {
}
}
+ case aigp-metric {
+ when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:aigp-metric')";
+ leaf aigp-metric {
+ type string;
+ description
+ "Set BGP AIGP attribute (AIGP Metric TLV)";
+ }
+ }
+
case as-path-prepend {
when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:as-path-prepend')";
choice as-path-prepend {
diff --git a/yang/frr-isisd.yang b/yang/frr-isisd.yang
index 0812c86fa..380fce385 100644
--- a/yang/frr-isisd.yang
+++ b/yang/frr-isisd.yang
@@ -1066,11 +1066,25 @@ module frr-isisd {
"If true, identify as L1/L2 router for inter-area traffic.";
}
- leaf overload {
- type boolean;
- default "false";
+ container overload {
description
- "If true, avoid any transit traffic.";
+ "Overload bit configuration.";
+ leaf enabled {
+ type boolean;
+ default "false";
+ description
+ "If true, avoid any transit traffic.";
+ }
+
+ leaf on-startup {
+ type uint32 {
+ range "0..86400";
+ }
+ units "seconds";
+ default "0";
+ description
+ "The duration the overload bit should be set on startup.";
+ }
}
leaf metric-style {
diff --git a/zebra/debug.c b/zebra/debug.c
index 69aaed33a..16aac7909 100644
--- a/zebra/debug.c
+++ b/zebra/debug.c
@@ -23,9 +23,7 @@
#include "command.h"
#include "debug.h"
-#ifndef VTYSH_EXTRACT_PL
#include "zebra/debug_clippy.c"
-#endif
/* For debug statement. */
unsigned long zebra_debug_event;
@@ -137,6 +135,9 @@ DEFUN_NOSH (show_debugging_zebra,
vty_out(vty, " Zebra PBR debugging is on\n");
hook_call(zebra_debug_show_debugging, vty);
+
+ cmd_show_lib_debugs(vty);
+
return CMD_SUCCESS;
}
diff --git a/zebra/dpdk/zebra_dplane_dpdk_vty.c b/zebra/dpdk/zebra_dplane_dpdk_vty.c
index 748bce9e3..d1814af3b 100644
--- a/zebra/dpdk/zebra_dplane_dpdk_vty.c
+++ b/zebra/dpdk/zebra_dplane_dpdk_vty.c
@@ -23,9 +23,7 @@
#include "lib/json.h"
#include "zebra/dpdk/zebra_dplane_dpdk.h"
-#ifndef VTYSH_EXTRACT_PL
#include "zebra/dpdk/zebra_dplane_dpdk_vty_clippy.c"
-#endif
#define ZD_STR "Zebra dataplane information\n"
#define ZD_DPDK_STR "DPDK offload information\n"
diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c
index d07c4c633..c5e1c113c 100644
--- a/zebra/dplane_fpm_nl.c
+++ b/zebra/dplane_fpm_nl.c
@@ -98,6 +98,7 @@ struct fpm_nl_ctx {
struct thread *t_read;
struct thread *t_write;
struct thread *t_event;
+ struct thread *t_nhg;
struct thread *t_dequeue;
/* zebra events. */
@@ -271,7 +272,7 @@ DEFUN(fpm_use_nhg, fpm_use_nhg_cmd,
return CMD_SUCCESS;
thread_add_event(gfnc->fthread->master, fpm_process_event, gfnc,
- FNE_TOGGLE_NHG, &gfnc->t_event);
+ FNE_TOGGLE_NHG, &gfnc->t_nhg);
return CMD_SUCCESS;
}
@@ -287,7 +288,7 @@ DEFUN(no_fpm_use_nhg, no_fpm_use_nhg_cmd,
return CMD_SUCCESS;
thread_add_event(gfnc->fthread->master, fpm_process_event, gfnc,
- FNE_TOGGLE_NHG, &gfnc->t_event);
+ FNE_TOGGLE_NHG, &gfnc->t_nhg);
return CMD_SUCCESS;
}
@@ -1275,7 +1276,7 @@ static void fpm_process_queue(struct thread *t)
static void fpm_process_event(struct thread *t)
{
struct fpm_nl_ctx *fnc = THREAD_ARG(t);
- int event = THREAD_VAL(t);
+ enum fpm_nl_events event = THREAD_VAL(t);
switch (event) {
case FNE_DISABLE:
@@ -1328,11 +1329,6 @@ static void fpm_process_event(struct thread *t)
if (IS_ZEBRA_DEBUG_FPM)
zlog_debug("%s: LSP walk finished", __func__);
break;
-
- default:
- if (IS_ZEBRA_DEBUG_FPM)
- zlog_debug("%s: unhandled event %d", __func__, event);
- break;
}
}
@@ -1372,6 +1368,8 @@ static int fpm_nl_finish_early(struct fpm_nl_ctx *fnc)
THREAD_OFF(fnc->t_ribwalk);
THREAD_OFF(fnc->t_rmacreset);
THREAD_OFF(fnc->t_rmacwalk);
+ THREAD_OFF(fnc->t_event);
+ THREAD_OFF(fnc->t_nhg);
thread_cancel_async(fnc->fthread->master, &fnc->t_read, NULL);
thread_cancel_async(fnc->fthread->master, &fnc->t_write, NULL);
thread_cancel_async(fnc->fthread->master, &fnc->t_connect, NULL);
diff --git a/zebra/interface.c b/zebra/interface.c
index c674b499a..32703b59b 100644
--- a/zebra/interface.c
+++ b/zebra/interface.c
@@ -2603,9 +2603,7 @@ static void interface_update_stats(void)
#endif /* HAVE_NET_RT_IFLIST */
}
-#ifndef VTYSH_EXTRACT_PL
#include "zebra/interface_clippy.c"
-#endif
/* Show all interfaces to vty. */
DEFPY(show_interface, show_interface_cmd,
"show interface vrf NAME$vrf_name [brief$brief] [json$uj]",
@@ -3279,14 +3277,8 @@ DEFUN (link_params_enable,
"Link-params: enable TE link parameters on interface %s",
ifp->name);
- if (!if_link_params_get(ifp)) {
- if (IS_ZEBRA_DEBUG_EVENT || IS_ZEBRA_DEBUG_MPLS)
- zlog_debug(
- "Link-params: failed to init TE link parameters %s",
- ifp->name);
-
- return CMD_WARNING_CONFIG_FAILED;
- }
+ if (!if_link_params_get(ifp))
+ if_link_params_enable(ifp);
/* force protocols to update LINK STATE due to parameters change */
if (if_is_operative(ifp))
@@ -3330,6 +3322,9 @@ DEFUN (link_params_metric,
metric = strtoul(argv[idx_number]->arg, NULL, 10);
+ if (!iflp)
+ iflp = if_link_params_enable(ifp);
+
/* Update TE metric if needed */
link_param_cmd_set_uint32(ifp, &iflp->te_metric, LP_TE_METRIC, metric);
@@ -3370,17 +3365,20 @@ DEFUN (link_params_maxbw,
/* Check that Maximum bandwidth is not lower than other bandwidth
* parameters */
- if ((bw <= iflp->max_rsv_bw) || (bw <= iflp->unrsv_bw[0])
- || (bw <= iflp->unrsv_bw[1]) || (bw <= iflp->unrsv_bw[2])
- || (bw <= iflp->unrsv_bw[3]) || (bw <= iflp->unrsv_bw[4])
- || (bw <= iflp->unrsv_bw[5]) || (bw <= iflp->unrsv_bw[6])
- || (bw <= iflp->unrsv_bw[7]) || (bw <= iflp->ava_bw)
- || (bw <= iflp->res_bw) || (bw <= iflp->use_bw)) {
+ if (iflp && ((bw <= iflp->max_rsv_bw) || (bw <= iflp->unrsv_bw[0]) ||
+ (bw <= iflp->unrsv_bw[1]) || (bw <= iflp->unrsv_bw[2]) ||
+ (bw <= iflp->unrsv_bw[3]) || (bw <= iflp->unrsv_bw[4]) ||
+ (bw <= iflp->unrsv_bw[5]) || (bw <= iflp->unrsv_bw[6]) ||
+ (bw <= iflp->unrsv_bw[7]) || (bw <= iflp->ava_bw) ||
+ (bw <= iflp->res_bw) || (bw <= iflp->use_bw))) {
vty_out(vty,
"Maximum Bandwidth could not be lower than others bandwidth\n");
return CMD_WARNING_CONFIG_FAILED;
}
+ if (!iflp)
+ iflp = if_link_params_enable(ifp);
+
/* Update Maximum Bandwidth if needed */
link_param_cmd_set_float(ifp, &iflp->max_bw, LP_MAX_BW, bw);
@@ -3406,13 +3404,16 @@ DEFUN (link_params_max_rsv_bw,
/* Check that bandwidth is not greater than maximum bandwidth parameter
*/
- if (bw > iflp->max_bw) {
+ if (iflp && bw > iflp->max_bw) {
vty_out(vty,
"Maximum Reservable Bandwidth could not be greater than Maximum Bandwidth (%g)\n",
iflp->max_bw);
return CMD_WARNING_CONFIG_FAILED;
}
+ if (!iflp)
+ iflp = if_link_params_enable(ifp);
+
/* Update Maximum Reservable Bandwidth if needed */
link_param_cmd_set_float(ifp, &iflp->max_rsv_bw, LP_MAX_RSV_BW, bw);
@@ -3448,13 +3449,16 @@ DEFUN (link_params_unrsv_bw,
/* Check that bandwidth is not greater than maximum bandwidth parameter
*/
- if (bw > iflp->max_bw) {
+ if (iflp && bw > iflp->max_bw) {
vty_out(vty,
"UnReserved Bandwidth could not be greater than Maximum Bandwidth (%g)\n",
iflp->max_bw);
return CMD_WARNING_CONFIG_FAILED;
}
+ if (!iflp)
+ iflp = if_link_params_enable(ifp);
+
/* Update Unreserved Bandwidth if needed */
link_param_cmd_set_float(ifp, &iflp->unrsv_bw[priority], LP_UNRSV_BW,
bw);
@@ -3479,6 +3483,9 @@ DEFUN (link_params_admin_grp,
return CMD_WARNING_CONFIG_FAILED;
}
+ if (!iflp)
+ iflp = if_link_params_enable(ifp);
+
/* Update Administrative Group if needed */
link_param_cmd_set_uint32(ifp, &iflp->admin_grp, LP_ADM_GRP, value);
@@ -3521,6 +3528,9 @@ DEFUN (link_params_inter_as,
return CMD_WARNING_CONFIG_FAILED;
}
+ if (!iflp)
+ iflp = if_link_params_enable(ifp);
+
as = strtoul(argv[idx_number]->arg, NULL, 10);
/* Update Remote IP and Remote AS fields if needed */
@@ -3548,6 +3558,9 @@ DEFUN (no_link_params_inter_as,
VTY_DECLVAR_CONTEXT(interface, ifp);
struct if_link_params *iflp = if_link_params_get(ifp);
+ if (!iflp)
+ return CMD_SUCCESS;
+
/* Reset Remote IP and AS neighbor */
iflp->rmt_as = 0;
iflp->rmt_ip.s_addr = 0;
@@ -3595,13 +3608,17 @@ DEFUN (link_params_delay,
* Therefore, it is also allowed that the average
* delay be equal to the min delay or max delay.
*/
- if (IS_PARAM_SET(iflp, LP_MM_DELAY)
- && (delay < iflp->min_delay || delay > iflp->max_delay)) {
+ if (iflp && IS_PARAM_SET(iflp, LP_MM_DELAY) &&
+ (delay < iflp->min_delay || delay > iflp->max_delay)) {
vty_out(vty,
"Average delay should be in range Min (%d) - Max (%d) delay\n",
iflp->min_delay, iflp->max_delay);
return CMD_WARNING_CONFIG_FAILED;
}
+
+ if (!iflp)
+ iflp = if_link_params_enable(ifp);
+
/* Update delay if value is not set or change */
if (IS_PARAM_UNSET(iflp, LP_DELAY) || iflp->av_delay != delay) {
iflp->av_delay = delay;
@@ -3626,6 +3643,10 @@ DEFUN (link_params_delay,
low, high);
return CMD_WARNING_CONFIG_FAILED;
}
+
+ if (!iflp)
+ iflp = if_link_params_enable(ifp);
+
/* Update Delays if needed */
if (IS_PARAM_UNSET(iflp, LP_DELAY)
|| IS_PARAM_UNSET(iflp, LP_MM_DELAY)
@@ -3656,6 +3677,9 @@ DEFUN (no_link_params_delay,
VTY_DECLVAR_CONTEXT(interface, ifp);
struct if_link_params *iflp = if_link_params_get(ifp);
+ if (!iflp)
+ return CMD_SUCCESS;
+
/* Unset Delays */
iflp->av_delay = 0;
UNSET_PARAM(iflp, LP_DELAY);
@@ -3683,6 +3707,9 @@ DEFUN (link_params_delay_var,
value = strtoul(argv[idx_number]->arg, NULL, 10);
+ if (!iflp)
+ iflp = if_link_params_enable(ifp);
+
/* Update Delay Variation if needed */
link_param_cmd_set_uint32(ifp, &iflp->delay_var, LP_DELAY_VAR, value);
@@ -3723,6 +3750,9 @@ DEFUN (link_params_pkt_loss,
if (fval > MAX_PKT_LOSS)
fval = MAX_PKT_LOSS;
+ if (!iflp)
+ iflp = if_link_params_enable(ifp);
+
/* Update Packet Loss if needed */
link_param_cmd_set_float(ifp, &iflp->pkt_loss, LP_PKT_LOSS, fval);
@@ -3762,13 +3792,16 @@ DEFUN (link_params_res_bw,
/* Check that bandwidth is not greater than maximum bandwidth parameter
*/
- if (bw > iflp->max_bw) {
+ if (iflp && bw > iflp->max_bw) {
vty_out(vty,
"Residual Bandwidth could not be greater than Maximum Bandwidth (%g)\n",
iflp->max_bw);
return CMD_WARNING_CONFIG_FAILED;
}
+ if (!iflp)
+ iflp = if_link_params_enable(ifp);
+
/* Update Residual Bandwidth if needed */
link_param_cmd_set_float(ifp, &iflp->res_bw, LP_RES_BW, bw);
@@ -3808,13 +3841,16 @@ DEFUN (link_params_ava_bw,
/* Check that bandwidth is not greater than maximum bandwidth parameter
*/
- if (bw > iflp->max_bw) {
+ if (iflp && bw > iflp->max_bw) {
vty_out(vty,
"Available Bandwidth could not be greater than Maximum Bandwidth (%g)\n",
iflp->max_bw);
return CMD_WARNING_CONFIG_FAILED;
}
+ if (!iflp)
+ iflp = if_link_params_enable(ifp);
+
/* Update Residual Bandwidth if needed */
link_param_cmd_set_float(ifp, &iflp->ava_bw, LP_AVA_BW, bw);
@@ -3854,13 +3890,16 @@ DEFUN (link_params_use_bw,
/* Check that bandwidth is not greater than maximum bandwidth parameter
*/
- if (bw > iflp->max_bw) {
+ if (iflp && bw > iflp->max_bw) {
vty_out(vty,
"Utilised Bandwidth could not be greater than Maximum Bandwidth (%g)\n",
iflp->max_bw);
return CMD_WARNING_CONFIG_FAILED;
}
+ if (!iflp)
+ iflp = if_link_params_enable(ifp);
+
/* Update Utilized Bandwidth if needed */
link_param_cmd_set_float(ifp, &iflp->use_bw, LP_USE_BW, bw);
diff --git a/zebra/main.c b/zebra/main.c
index 46cf2eea7..3de97943f 100644
--- a/zebra/main.c
+++ b/zebra/main.c
@@ -229,6 +229,7 @@ void zebra_finalize(struct thread *dummy)
zebra_router_terminate();
+ ns_terminate();
frr_fini();
exit(0);
}
diff --git a/zebra/netconf_netlink.c b/zebra/netconf_netlink.c
index 56f56bfe6..4c30544e5 100644
--- a/zebra/netconf_netlink.c
+++ b/zebra/netconf_netlink.c
@@ -106,9 +106,11 @@ int netlink_netconf_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
* to do a good job of not sending data that is mixed/matched
* across families
*/
+#ifdef AF_MPLS
if (ncm->ncm_family == AF_MPLS)
afi = AFI_IP;
else
+#endif /* AF_MPLS */
afi = family2afi(ncm->ncm_family);
netlink_parse_rtattr(tb, NETCONFA_MAX, netconf_rta(ncm), len);
diff --git a/zebra/rib.h b/zebra/rib.h
index 99f52bcd4..166500fa5 100644
--- a/zebra/rib.h
+++ b/zebra/rib.h
@@ -158,6 +158,13 @@ struct route_entry {
* differs from the rib/normal set of nexthops.
*/
#define ROUTE_ENTRY_USE_FIB_NHG 0x40
+/*
+ * Route entries that are going to the dplane for a Route Replace
+ * let's note the fact that this is happening. This will
+ * be useful when zebra is determing if a route can be
+ * used for nexthops
+ */
+#define ROUTE_ENTRY_ROUTE_REPLACING 0x80
/* Sequence value incremented for each dataplane operation */
uint32_t dplane_sequence;
diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c
index e883033d5..2396dfe4d 100644
--- a/zebra/rt_netlink.c
+++ b/zebra/rt_netlink.c
@@ -803,6 +803,9 @@ static int netlink_route_change_read_unicast(struct nlmsghdr *h, ns_id_t ns_id,
if (rtm->rtm_flags & RTM_F_OFFLOAD_FAILED)
flags |= ZEBRA_FLAG_OFFLOAD_FAILED;
+ if (h->nlmsg_flags & NLM_F_APPEND)
+ flags |= ZEBRA_FLAG_OUTOFSYNC;
+
/* Route which inserted by Zebra. */
if (selfroute) {
flags |= ZEBRA_FLAG_SELFROUTE;
@@ -1540,6 +1543,16 @@ static bool _netlink_route_build_singlepath(const struct prefix *p,
ctx->table))
return false;
break;
+ case ZEBRA_SEG6_LOCAL_ACTION_END_DT46:
+ if (!nl_attr_put32(nlmsg, req_size,
+ SEG6_LOCAL_ACTION,
+ SEG6_LOCAL_ACTION_END_DT46))
+ return false;
+ if (!nl_attr_put32(nlmsg, req_size,
+ SEG6_LOCAL_VRFTABLE,
+ ctx->table))
+ return false;
+ break;
default:
zlog_err("%s: unsupport seg6local behaviour action=%u",
__func__,
@@ -2402,7 +2415,8 @@ int kernel_get_ipmr_sg_stats(struct zebra_vrf *zvrf, void *in)
static bool _netlink_nexthop_build_group(struct nlmsghdr *n, size_t req_size,
uint32_t id,
const struct nh_grp *z_grp,
- const uint8_t count)
+ const uint8_t count, bool resilient,
+ const struct nhg_resilience *nhgr)
{
struct nexthop_grp grp[count];
/* Need space for max group size, "/", and null term */
@@ -2432,6 +2446,24 @@ static bool _netlink_nexthop_build_group(struct nlmsghdr *n, size_t req_size,
if (!nl_attr_put(n, req_size, NHA_GROUP, grp,
count * sizeof(*grp)))
return false;
+
+ if (resilient) {
+ struct rtattr *nest;
+
+ nest = nl_attr_nest(n, req_size, NHA_RES_GROUP);
+
+ nl_attr_put16(n, req_size, NHA_RES_GROUP_BUCKETS,
+ nhgr->buckets);
+ nl_attr_put32(n, req_size, NHA_RES_GROUP_IDLE_TIMER,
+ nhgr->idle_timer * 1000);
+ nl_attr_put32(n, req_size,
+ NHA_RES_GROUP_UNBALANCED_TIMER,
+ nhgr->unbalanced_timer * 1000);
+ nl_attr_nest_end(n, nest);
+
+ nl_attr_put16(n, req_size, NHA_GROUP_TYPE,
+ NEXTHOP_GRP_TYPE_RES);
+ }
}
if (IS_ZEBRA_DEBUG_KERNEL)
@@ -2528,10 +2560,16 @@ ssize_t netlink_nexthop_msg_encode(uint16_t cmd,
* other ids.
*/
if (dplane_ctx_get_nhe_nh_grp_count(ctx)) {
+ const struct nexthop_group *nhg;
+ const struct nhg_resilience *nhgr;
+
+ nhg = dplane_ctx_get_nhe_ng(ctx);
+ nhgr = &nhg->nhgr;
if (!_netlink_nexthop_build_group(
&req->n, buflen, id,
dplane_ctx_get_nhe_nh_grp(ctx),
- dplane_ctx_get_nhe_nh_grp_count(ctx)))
+ dplane_ctx_get_nhe_nh_grp_count(ctx),
+ !!nhgr->buckets, nhgr))
return 0;
} else {
const struct nexthop *nh =
@@ -2706,6 +2744,18 @@ ssize_t netlink_nexthop_msg_encode(uint16_t cmd,
ctx->table))
return 0;
break;
+ case SEG6_LOCAL_ACTION_END_DT46:
+ if (!nl_attr_put32(
+ &req->n, buflen,
+ SEG6_LOCAL_ACTION,
+ SEG6_LOCAL_ACTION_END_DT46))
+ return 0;
+ if (!nl_attr_put32(
+ &req->n, buflen,
+ SEG6_LOCAL_VRFTABLE,
+ ctx->table))
+ return 0;
+ break;
default:
zlog_err("%s: unsupport seg6local behaviour action=%u",
__func__, action);
@@ -2963,7 +3013,8 @@ static struct nexthop netlink_nexthop_process_nh(struct rtattr **tb,
}
static int netlink_nexthop_process_group(struct rtattr **tb,
- struct nh_grp *z_grp, int z_grp_size)
+ struct nh_grp *z_grp, int z_grp_size,
+ struct nhg_resilience *nhgr)
{
uint8_t count = 0;
/* linux/nexthop.h group struct */
@@ -2982,6 +3033,36 @@ static int netlink_nexthop_process_group(struct rtattr **tb,
z_grp[i].id = n_grp[i].id;
z_grp[i].weight = n_grp[i].weight + 1;
}
+
+ memset(nhgr, 0, sizeof(*nhgr));
+ if (tb[NHA_RES_GROUP]) {
+ struct rtattr *tbn[NHA_RES_GROUP_MAX + 1];
+ struct rtattr *rta;
+ struct rtattr *res_group = tb[NHA_RES_GROUP];
+
+ netlink_parse_rtattr_nested(tbn, NHA_RES_GROUP_MAX, res_group);
+
+ if (tbn[NHA_RES_GROUP_BUCKETS]) {
+ rta = tbn[NHA_RES_GROUP_BUCKETS];
+ nhgr->buckets = *(uint16_t *)RTA_DATA(rta);
+ }
+
+ if (tbn[NHA_RES_GROUP_IDLE_TIMER]) {
+ rta = tbn[NHA_RES_GROUP_IDLE_TIMER];
+ nhgr->idle_timer = *(uint32_t *)RTA_DATA(rta);
+ }
+
+ if (tbn[NHA_RES_GROUP_UNBALANCED_TIMER]) {
+ rta = tbn[NHA_RES_GROUP_UNBALANCED_TIMER];
+ nhgr->unbalanced_timer = *(uint32_t *)RTA_DATA(rta);
+ }
+
+ if (tbn[NHA_RES_GROUP_UNBALANCED_TIME]) {
+ rta = tbn[NHA_RES_GROUP_UNBALANCED_TIME];
+ nhgr->unbalanced_time = *(uint64_t *)RTA_DATA(rta);
+ }
+ }
+
return count;
}
@@ -3065,13 +3146,15 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
if (h->nlmsg_type == RTM_NEWNEXTHOP) {
+ struct nhg_resilience nhgr = {};
+
if (tb[NHA_GROUP]) {
/**
* If this is a group message its only going to have
* an array of nexthop IDs associated with it
*/
grp_count = netlink_nexthop_process_group(
- tb, grp, array_size(grp));
+ tb, grp, array_size(grp), &nhgr);
} else {
if (tb[NHA_BLACKHOLE]) {
/**
@@ -3103,7 +3186,7 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup)
}
if (zebra_nhg_kernel_find(id, &nh, grp, grp_count, vrf_id, afi,
- type, startup))
+ type, startup, &nhgr))
return -1;
} else if (h->nlmsg_type == RTM_DELNEXTHOP)
diff --git a/zebra/rtadv.c b/zebra/rtadv.c
index 127888d65..a8ec60844 100644
--- a/zebra/rtadv.c
+++ b/zebra/rtadv.c
@@ -51,9 +51,7 @@ static uint32_t interfaces_configured_for_ra_from_bgp;
#if defined(HAVE_RTADV)
-#ifndef VTYSH_EXTRACT_PL
#include "zebra/rtadv_clippy.c"
-#endif
DEFINE_MTYPE_STATIC(ZEBRA, RTADV_PREFIX, "Router Advertisement Prefix");
DEFINE_MTYPE_STATIC(ZEBRA, ADV_IF, "Advertised Interface");
diff --git a/zebra/subdir.am b/zebra/subdir.am
index 298b71598..984293149 100644
--- a/zebra/subdir.am
+++ b/zebra/subdir.am
@@ -4,29 +4,6 @@
if ZEBRA
sbin_PROGRAMS += zebra/zebra
-vtysh_scan += \
- zebra/debug.c \
- zebra/interface.c \
- zebra/router-id.c \
- zebra/rtadv.c \
- zebra/zebra_gr.c \
- zebra/zebra_mlag_vty.c \
- zebra/zebra_evpn_mh.c \
- zebra/zebra_mpls_vty.c \
- zebra/zebra_srv6_vty.c \
- zebra/zebra_ptm.c \
- zebra/zebra_pw.c \
- zebra/zebra_routemap.c \
- zebra/zebra_vty.c \
- zebra/zserv.c \
- zebra/zebra_vrf.c \
- zebra/dpdk/zebra_dplane_dpdk_vty.c \
- # end
-
-# can be loaded as DSO - always include for vtysh
-vtysh_scan += zebra/irdp_interface.c
-vtysh_scan += zebra/zebra_fpm.c
-
vtysh_daemons += zebra
if IRDP
@@ -255,8 +232,6 @@ module_LTLIBRARIES += zebra/dplane_fpm_nl.la
zebra_dplane_fpm_nl_la_SOURCES = zebra/dplane_fpm_nl.c
zebra_dplane_fpm_nl_la_LDFLAGS = $(MODULE_LDFLAGS)
zebra_dplane_fpm_nl_la_LIBADD =
-
-vtysh_scan += zebra/dplane_fpm_nl.c
endif
if NETLINK_DEBUG
diff --git a/zebra/tc_netlink.c b/zebra/tc_netlink.c
index 4fb0241d1..afa03a4fa 100644
--- a/zebra/tc_netlink.c
+++ b/zebra/tc_netlink.c
@@ -25,7 +25,7 @@
#ifdef HAVE_NETLINK
-#include <linux/if_ether.h>
+#include <netinet/if_ether.h>
#include <sys/socket.h>
#include "if.h"
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index 761ba789b..130fb972d 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -232,11 +232,6 @@ int zsend_interface_link_params(struct zserv *client, struct interface *ifp)
{
struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ);
- if (!ifp->link_params) {
- stream_free(s);
- return 0;
- }
-
zclient_create_header(s, ZEBRA_INTERFACE_LINK_PARAMS, ifp->vrf->vrf_id);
/* Add Interface Index */
@@ -1879,6 +1874,10 @@ static int zapi_nhg_decode(struct stream *s, int cmd, struct zapi_nhg *api_nhg)
if (cmd == ZEBRA_NHG_DEL)
goto done;
+ STREAM_GETW(s, api_nhg->resilience.buckets);
+ STREAM_GETL(s, api_nhg->resilience.idle_timer);
+ STREAM_GETL(s, api_nhg->resilience.unbalanced_timer);
+
/* Nexthops */
STREAM_GETW(s, api_nhg->nexthop_num);
@@ -2003,6 +2002,8 @@ static void zread_nhg_add(ZAPI_HANDLER_ARGS)
nhe->nhg.nexthop = nhg->nexthop;
nhg->nexthop = NULL;
+ nhe->nhg.nhgr = api_nhg.resilience;
+
if (bnhg) {
nhe->backup_info = bnhg;
bnhg = NULL;
@@ -2605,8 +2606,10 @@ static void zread_sr_policy_set(ZAPI_HANDLER_ARGS)
return;
policy = zebra_sr_policy_find(zp.color, &zp.endpoint);
- if (!policy)
+ if (!policy) {
policy = zebra_sr_policy_add(zp.color, &zp.endpoint, zp.name);
+ policy->sock = client->sock;
+ }
/* TODO: per-VRF list of SR-TE policies. */
policy->zvrf = zvrf;
@@ -2709,6 +2712,7 @@ int zsend_srv6_manager_get_locator_chunk_response(struct zserv *client,
chunk.keep = 0;
chunk.proto = client->proto;
chunk.instance = client->instance;
+ chunk.flags = loc->flags;
zclient_create_header(s, ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK, vrf_id);
zapi_srv6_locator_chunk_encode(s, &chunk);
diff --git a/zebra/zebra_evpn_mh.c b/zebra/zebra_evpn_mh.c
index 043ea0f24..01ea9c5b9 100644
--- a/zebra/zebra_evpn_mh.c
+++ b/zebra/zebra_evpn_mh.c
@@ -2759,6 +2759,12 @@ bool zebra_evpn_is_if_es_capable(struct zebra_if *zif)
if (zif->zif_type == ZEBRA_IF_BOND)
return true;
+ /* relax the checks to allow config to be applied in zebra
+ * before interface is rxed from the kernel
+ */
+ if (zif->ifp->ifindex == IFINDEX_INTERNAL)
+ return true;
+
/* XXX: allow swpX i.e. a regular ethernet port to be an ES link too */
return false;
}
@@ -3252,9 +3258,7 @@ int zebra_evpn_mh_if_write(struct vty *vty, struct interface *ifp)
return 0;
}
-#ifndef VTYSH_EXTRACT_PL
#include "zebra/zebra_evpn_mh_clippy.c"
-#endif
/* CLI for setting an ES in bypass mode */
DEFPY_HIDDEN(zebra_evpn_es_bypass, zebra_evpn_es_bypass_cmd,
"[no] evpn mh bypass",
@@ -4028,4 +4032,6 @@ void zebra_evpn_mh_terminate(void)
hash_free(zmh_info->nhg_table);
hash_free(zmh_info->nh_ip_table);
bf_free(zmh_info->nh_id_bitmap);
+
+ XFREE(MTYPE_ZMH_INFO, zrouter.mh_info);
}
diff --git a/zebra/zebra_fpm.c b/zebra/zebra_fpm.c
index 1b2753377..f9f4ee476 100644
--- a/zebra/zebra_fpm.c
+++ b/zebra/zebra_fpm.c
@@ -899,7 +899,6 @@ static inline int zfpm_encode_route(rib_dest_t *dest, struct route_entry *re,
len = zfpm_netlink_encode_route(cmd, dest, re, in_buf,
in_buf_len);
assert(fpm_msg_align(len) == len);
- *msg_type = FPM_MSG_TYPE_NETLINK;
#endif /* HAVE_NETLINK */
break;
@@ -1841,12 +1840,15 @@ DEFUN (clear_zebra_fpm_stats,
/*
* update fpm connection information
*/
-DEFUN ( fpm_remote_ip,
+DEFUN (fpm_remote_ip,
fpm_remote_ip_cmd,
- "fpm connection ip A.B.C.D port (1-65535)",
- "fpm connection remote ip and port\n"
- "Remote fpm server ip A.B.C.D\n"
- "Enter ip ")
+ "fpm connection ip A.B.C.D port (1-65535)",
+ "Forwarding Path Manager\n"
+ "Configure FPM connection\n"
+ "Connect to IPv4 address\n"
+ "Connect to IPv4 address\n"
+ "TCP port number\n"
+ "TCP port number\n")
{
in_addr_t fpm_server;
@@ -1867,13 +1869,16 @@ DEFUN ( fpm_remote_ip,
return CMD_SUCCESS;
}
-DEFUN ( no_fpm_remote_ip,
+DEFUN (no_fpm_remote_ip,
no_fpm_remote_ip_cmd,
- "no fpm connection ip A.B.C.D port (1-65535)",
- "fpm connection remote ip and port\n"
- "Connection\n"
- "Remote fpm server ip A.B.C.D\n"
- "Enter ip ")
+ "no fpm connection ip A.B.C.D port (1-65535)",
+ NO_STR
+ "Forwarding Path Manager\n"
+ "Remove configured FPM connection\n"
+ "Connect to IPv4 address\n"
+ "Connect to IPv4 address\n"
+ "TCP port number\n"
+ "TCP port number\n")
{
if (zfpm_g->fpm_server != inet_addr(argv[4]->arg)
|| zfpm_g->fpm_port != atoi(argv[6]->arg))
diff --git a/zebra/zebra_mlag_vty.c b/zebra/zebra_mlag_vty.c
index ebaaf03da..a1c544d5d 100644
--- a/zebra/zebra_mlag_vty.c
+++ b/zebra/zebra_mlag_vty.c
@@ -29,9 +29,7 @@
#include "debug.h"
#include "zapi_msg.h"
-#ifndef VTYSH_EXTRACT_PL
#include "zebra/zebra_mlag_vty_clippy.c"
-#endif
DEFUN_HIDDEN (show_mlag,
show_mlag_cmd,
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index 1964c763c..5fadd4c82 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -563,6 +563,15 @@ bool zebra_nhg_hash_equal(const void *arg1, const void *arg2)
if (nhe1->afi != nhe2->afi)
return false;
+ if (nhe1->nhg.nhgr.buckets != nhe2->nhg.nhgr.buckets)
+ return false;
+
+ if (nhe1->nhg.nhgr.idle_timer != nhe2->nhg.nhgr.idle_timer)
+ return false;
+
+ if (nhe1->nhg.nhgr.unbalanced_timer != nhe2->nhg.nhgr.unbalanced_timer)
+ return false;
+
/* Nexthops should be in-order, so we simply compare them in-place */
for (nexthop1 = nhe1->nhg.nexthop, nexthop2 = nhe2->nhg.nexthop;
nexthop1 && nexthop2;
@@ -621,7 +630,8 @@ bool zebra_nhg_hash_id_equal(const void *arg1, const void *arg2)
static int zebra_nhg_process_grp(struct nexthop_group *nhg,
struct nhg_connected_tree_head *depends,
- struct nh_grp *grp, uint8_t count)
+ struct nh_grp *grp, uint8_t count,
+ struct nhg_resilience *resilience)
{
nhg_connected_tree_init(depends);
@@ -652,6 +662,9 @@ static int zebra_nhg_process_grp(struct nexthop_group *nhg,
copy_nexthops(&nhg->nexthop, depend->nhg.nexthop, NULL);
}
+ if (resilience)
+ nhg->nhgr = *resilience;
+
return 0;
}
@@ -985,6 +998,11 @@ static struct nh_grp *nhg_ctx_get_grp(struct nhg_ctx *ctx)
return ctx->u.grp;
}
+static struct nhg_resilience *nhg_ctx_get_resilience(struct nhg_ctx *ctx)
+{
+ return &ctx->resilience;
+}
+
static struct nhg_ctx *nhg_ctx_new(void)
{
struct nhg_ctx *new;
@@ -1018,7 +1036,8 @@ done:
static struct nhg_ctx *nhg_ctx_init(uint32_t id, struct nexthop *nh,
struct nh_grp *grp, vrf_id_t vrf_id,
- afi_t afi, int type, uint8_t count)
+ afi_t afi, int type, uint8_t count,
+ struct nhg_resilience *resilience)
{
struct nhg_ctx *ctx = NULL;
@@ -1030,6 +1049,9 @@ static struct nhg_ctx *nhg_ctx_init(uint32_t id, struct nexthop *nh,
ctx->type = type;
ctx->count = count;
+ if (resilience)
+ ctx->resilience = *resilience;
+
if (count)
/* Copy over the array */
memcpy(&ctx->u.grp, grp, count * sizeof(struct nh_grp));
@@ -1176,7 +1198,8 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx)
if (nhg_ctx_get_count(ctx)) {
nhg = nexthop_group_new();
if (zebra_nhg_process_grp(nhg, &nhg_depends,
- nhg_ctx_get_grp(ctx), count)) {
+ nhg_ctx_get_grp(ctx), count,
+ nhg_ctx_get_resilience(ctx))) {
depends_decrement_free(&nhg_depends);
nexthop_group_delete(&nhg);
return -ENOENT;
@@ -1306,7 +1329,7 @@ int nhg_ctx_process(struct nhg_ctx *ctx)
/* Kernel-side, you either get a single new nexthop or a array of ID's */
int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp,
uint8_t count, vrf_id_t vrf_id, afi_t afi, int type,
- int startup)
+ int startup, struct nhg_resilience *nhgr)
{
struct nhg_ctx *ctx = NULL;
@@ -1320,7 +1343,7 @@ int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh, struct nh_grp *grp,
*/
id_counter = id;
- ctx = nhg_ctx_init(id, nh, grp, vrf_id, afi, type, count);
+ ctx = nhg_ctx_init(id, nh, grp, vrf_id, afi, type, count, nhgr);
nhg_ctx_set_op(ctx, NHG_CTX_OP_NEW);
/* Under statup conditions, we need to handle them immediately
@@ -1343,7 +1366,7 @@ int zebra_nhg_kernel_del(uint32_t id, vrf_id_t vrf_id)
{
struct nhg_ctx *ctx = NULL;
- ctx = nhg_ctx_init(id, NULL, NULL, vrf_id, 0, 0, 0);
+ ctx = nhg_ctx_init(id, NULL, NULL, vrf_id, 0, 0, 0, NULL);
nhg_ctx_set_op(ctx, NHG_CTX_OP_DEL);
@@ -2369,11 +2392,33 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe,
resolved = 0;
- /* Only useful if installed */
- if (!CHECK_FLAG(match->status, ROUTE_ENTRY_INSTALLED)) {
+ /*
+ * Only useful if installed or being Route Replacing
+ * Why Being Route Replaced as well?
+ * Imagine a route A and route B( that depends on A )
+ * for recursive resolution and A already exists in the
+ * zebra rib. If zebra receives the routes
+ * for resolution at aproximately the same time in the [
+ * B, A ] order on the workQ. If this happens then
+ * normal route resolution will happen and B will be
+ * resolved successfully and then A will be resolved
+ * successfully. Now imagine the reversed order [A, B].
+ * A will be resolved and then scheduled for installed
+ * (Thus not having the ROUTE_ENTRY_INSTALLED flag ). B
+ * will then get resolved and fail to be installed
+ * because the original below test. Let's `loosen` this
+ * up a tiny bit and allow the
+ * ROUTE_ENTRY_ROUTE_REPLACING flag ( that is set when a
+ * Route Replace operation is being initiated on A now )
+ * to now satisfy this situation. This will allow
+ * either order in the workQ to work properly.
+ */
+ if (!CHECK_FLAG(match->status, ROUTE_ENTRY_INSTALLED) &&
+ !CHECK_FLAG(match->status,
+ ROUTE_ENTRY_ROUTE_REPLACING)) {
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
zlog_debug(
- "%s: match %p (%pNG) not installed",
+ "%s: match %p (%pNG) not installed or being Route Replaced",
__func__, match, match->nhe);
goto done_with_match;
@@ -2618,10 +2663,8 @@ skip_check:
if (ret == RMAP_DENYMATCH) {
if (IS_ZEBRA_DEBUG_RIB) {
zlog_debug(
- "%u:%pRN: Filtering out with NH out %s due to route map",
- re->vrf_id, rn,
- ifindex2ifname(nexthop->ifindex,
- nexthop->vrf_id));
+ "%u:%pRN: Filtering out with NH %pNHv due to route map",
+ re->vrf_id, rn, nexthop);
}
UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE);
}
@@ -3324,6 +3367,7 @@ struct nhg_hash_entry *zebra_nhg_proto_add(uint32_t id, int type,
zebra_nhe_init(&lookup, afi, nhg->nexthop);
lookup.nhg.nexthop = nhg->nexthop;
+ lookup.nhg.nhgr = nhg->nhgr;
lookup.id = id;
lookup.type = type;
diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h
index 62f71f943..9b925bf10 100644
--- a/zebra/zebra_nhg.h
+++ b/zebra/zebra_nhg.h
@@ -228,6 +228,7 @@ struct nhg_ctx {
struct nh_grp grp[MULTIPATH_NUM];
} u;
+ struct nhg_resilience resilience;
enum nhg_ctx_op_e op;
enum nhg_ctx_status status;
};
@@ -308,7 +309,8 @@ void nhg_ctx_free(struct nhg_ctx **ctx);
extern int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh,
struct nh_grp *grp, uint8_t count,
vrf_id_t vrf_id, afi_t afi, int type,
- int startup);
+ int startup,
+ struct nhg_resilience *resilience);
/* Del via kernel */
extern int zebra_nhg_kernel_del(uint32_t id, vrf_id_t vrf_id);
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index fceaaaa9f..54ef4768e 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -292,13 +292,16 @@ static char *_dump_re_status(const struct route_entry *re, char *buf,
}
snprintfrr(
- buf, len, "%s%s%s%s%s%s%s",
+ buf, len, "%s%s%s%s%s%s%s%s",
CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED) ? "Removed " : "",
CHECK_FLAG(re->status, ROUTE_ENTRY_CHANGED) ? "Changed " : "",
CHECK_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED)
? "Label Changed "
: "",
CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED) ? "Queued " : "",
+ CHECK_FLAG(re->status, ROUTE_ENTRY_ROUTE_REPLACING)
+ ? "Replacing"
+ : "",
CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED) ? "Installed "
: "",
CHECK_FLAG(re->status, ROUTE_ENTRY_FAILED) ? "Failed " : "",
@@ -713,6 +716,7 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re,
if (old) {
SET_FLAG(old->status, ROUTE_ENTRY_QUEUED);
+ SET_FLAG(re->status, ROUTE_ENTRY_ROUTE_REPLACING);
/* Free old FIB nexthop group */
UNSET_FLAG(old->status, ROUTE_ENTRY_USE_FIB_NHG);
@@ -1538,6 +1542,7 @@ static void zebra_rib_fixup_system(struct route_node *rn)
SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED);
UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED);
+ UNSET_FLAG(re->status, ROUTE_ENTRY_ROUTE_REPLACING);
for (ALL_NEXTHOPS(re->nhe->nhg, nhop)) {
if (CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_RECURSIVE))
@@ -1995,8 +2000,12 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
} else {
if (!zrouter.asic_offloaded ||
(CHECK_FLAG(re->flags, ZEBRA_FLAG_OFFLOADED) ||
- CHECK_FLAG(re->flags, ZEBRA_FLAG_OFFLOAD_FAILED)))
+ CHECK_FLAG(re->flags,
+ ZEBRA_FLAG_OFFLOAD_FAILED))) {
+ UNSET_FLAG(re->status,
+ ROUTE_ENTRY_ROUTE_REPLACING);
UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED);
+ }
}
}
@@ -2252,8 +2261,10 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx)
}
/* Ensure we clear the QUEUED flag */
- if (!zrouter.asic_offloaded)
+ if (!zrouter.asic_offloaded) {
UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED);
+ UNSET_FLAG(re->status, ROUTE_ENTRY_ROUTE_REPLACING);
+ }
/* Is this a notification that ... matters? We mostly care about
* the route that is currently selected for installation; we may also
diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c
index 2cc84a1f7..13d1995d5 100644
--- a/zebra/zebra_routemap.c
+++ b/zebra/zebra_routemap.c
@@ -40,9 +40,7 @@
#include "zebra/zebra_rnh.h"
#include "zebra/zebra_routemap.h"
-#ifndef VTYSH_EXTRACT_PL
#include "zebra/zebra_routemap_clippy.c"
-#endif
static uint32_t zebra_rmap_update_timer = ZEBRA_RMAP_DEFAULT_UPDATE_TIMER;
static struct thread *zebra_t_rmap_update = NULL;
diff --git a/zebra/zebra_srte.c b/zebra/zebra_srte.c
index c0f18dd09..7d95607fc 100644
--- a/zebra/zebra_srte.c
+++ b/zebra/zebra_srte.c
@@ -384,6 +384,23 @@ int zebra_sr_policy_label_update(mpls_label_t label,
return 0;
}
+static int zebra_srte_client_close_cleanup(struct zserv *client)
+{
+ int sock = client->sock;
+ struct zebra_sr_policy *policy;
+
+ if (!sock)
+ return 0;
+
+ RB_FOREACH (policy, zebra_sr_policy_instance_head,
+ &zebra_sr_policy_instances) {
+ if (policy->sock == sock)
+ zebra_sr_policy_del(policy);
+ }
+ return 1;
+}
+
void zebra_srte_init(void)
{
+ hook_register(zserv_client_close, zebra_srte_client_close_cleanup);
}
diff --git a/zebra/zebra_srte.h b/zebra/zebra_srte.h
index fe7780944..dff2f595f 100644
--- a/zebra/zebra_srte.h
+++ b/zebra/zebra_srte.h
@@ -45,6 +45,7 @@ struct zebra_sr_policy {
struct zapi_srte_tunnel segment_list;
struct zebra_lsp *lsp;
struct zebra_vrf *zvrf;
+ int sock;
};
RB_HEAD(zebra_sr_policy_instance_head, zebra_sr_policy);
RB_PROTOTYPE(zebra_sr_policy_instance_head, zebra_sr_policy, entry,
diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c
index 36506cacc..d61e4f804 100644
--- a/zebra/zebra_srv6.c
+++ b/zebra/zebra_srv6.c
@@ -177,6 +177,58 @@ struct srv6_locator *zebra_srv6_locator_lookup(const char *name)
return NULL;
}
+void zebra_notify_srv6_locator_add(struct srv6_locator *locator)
+{
+ struct listnode *node;
+ struct zserv *client;
+
+ /*
+ * Notify new locator info to zclients.
+ *
+ * The srv6 locators and their prefixes are managed by zserv(zebra).
+ * And an actual configuration the srv6 sid in the srv6 locator is done
+ * by zclient(bgpd, isisd, etc). The configuration of each locator
+ * allocation and specify it by zserv and zclient should be
+ * asynchronous. For that, zclient should be received the event via
+ * ZAPI when a srv6 locator is added on zebra.
+ * Basically, in SRv6, adding/removing SRv6 locators is performed less
+ * frequently than adding rib entries, so a broad to all zclients will
+ * not degrade the overall performance of FRRouting.
+ */
+ for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client))
+ zsend_zebra_srv6_locator_add(client, locator);
+}
+
+void zebra_notify_srv6_locator_delete(struct srv6_locator *locator)
+{
+ struct listnode *n;
+ struct srv6_locator_chunk *c;
+ struct zserv *client;
+
+ /*
+ * Notify deleted locator info to zclients if needed.
+ *
+ * zclient(bgpd,isisd,etc) allocates a sid from srv6 locator chunk and
+ * uses it for its own purpose. For example, in the case of BGP L3VPN,
+ * the SID assigned to vpn unicast rib will be given.
+ * And when the locator is deleted by zserv(zebra), those SIDs need to
+ * be withdrawn. The zclient must initiate the withdrawal of the SIDs
+ * by ZEBRA_SRV6_LOCATOR_DELETE, and this notification is sent to the
+ * owner of each chunk.
+ */
+ for (ALL_LIST_ELEMENTS_RO((struct list *)locator->chunks, n, c)) {
+ if (c->proto == ZEBRA_ROUTE_SYSTEM)
+ continue;
+ client = zserv_find_client(c->proto, c->instance);
+ if (!client) {
+ zlog_warn("Not found zclient(proto=%u, instance=%u).",
+ c->proto, c->instance);
+ continue;
+ }
+ zsend_zebra_srv6_locator_delete(client, locator);
+ }
+}
+
struct zebra_srv6 *zebra_srv6_get_default(void)
{
static struct zebra_srv6 srv6;
diff --git a/zebra/zebra_srv6.h b/zebra/zebra_srv6.h
index 84fcc305b..f320b9ca0 100644
--- a/zebra/zebra_srv6.h
+++ b/zebra/zebra_srv6.h
@@ -61,6 +61,9 @@ extern void zebra_srv6_locator_add(struct srv6_locator *locator);
extern void zebra_srv6_locator_delete(struct srv6_locator *locator);
extern struct srv6_locator *zebra_srv6_locator_lookup(const char *name);
+void zebra_notify_srv6_locator_add(struct srv6_locator *locator);
+void zebra_notify_srv6_locator_delete(struct srv6_locator *locator);
+
extern void zebra_srv6_init(void);
extern struct zebra_srv6 *zebra_srv6_get_default(void);
extern bool zebra_srv6_is_enable(void);
diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c
index 62ce17326..1221365d4 100644
--- a/zebra/zebra_srv6_vty.c
+++ b/zebra/zebra_srv6_vty.c
@@ -40,9 +40,7 @@
#include "zebra/zebra_routemap.h"
#include "zebra/zebra_dplane.h"
-#ifndef VTYSH_EXTRACT_PL
#include "zebra/zebra_srv6_vty_clippy.c"
-#endif
static int zebra_sr_config(struct vty *vty);
@@ -167,8 +165,15 @@ DEFUN (show_srv6_locator_detail,
prefix2str(&locator->prefix, str, sizeof(str));
vty_out(vty, "Name: %s\n", locator->name);
vty_out(vty, "Prefix: %s\n", str);
+ vty_out(vty, "Block-Bit-Len: %u\n", locator->block_bits_length);
+ vty_out(vty, "Node-Bit-Len: %u\n", locator->node_bits_length);
vty_out(vty, "Function-Bit-Len: %u\n",
locator->function_bits_length);
+ vty_out(vty, "Argument-Bit-Len: %u\n",
+ locator->argument_bits_length);
+
+ if (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID))
+ vty_out(vty, "Behavior: uSID\n");
vty_out(vty, "Chunks:\n");
for (ALL_LIST_ELEMENTS_RO((struct list *)locator->chunks, node,
@@ -271,35 +276,64 @@ DEFUN (no_srv6_locator,
DEFPY (locator_prefix,
locator_prefix_cmd,
- "prefix X:X::X:X/M$prefix [func-bits (16-64)$func_bit_len]",
+ "prefix X:X::X:X/M$prefix [func-bits (0-64)$func_bit_len] \
+ [block-len (16-64)$block_bit_len] [node-len (16-64)$node_bit_len]",
"Configure SRv6 locator prefix\n"
"Specify SRv6 locator prefix\n"
"Configure SRv6 locator function length in bits\n"
- "Specify SRv6 locator function length in bits\n")
+ "Specify SRv6 locator function length in bits\n"
+ "Configure SRv6 locator block length in bits\n"
+ "Specify SRv6 locator block length in bits\n"
+ "Configure SRv6 locator node length in bits\n"
+ "Specify SRv6 locator node length in bits\n")
{
VTY_DECLVAR_CONTEXT(srv6_locator, locator);
struct srv6_locator_chunk *chunk = NULL;
struct listnode *node = NULL;
locator->prefix = *prefix;
+ func_bit_len = func_bit_len ?: ZEBRA_SRV6_FUNCTION_LENGTH;
+
+ /* Resolve optional arguments */
+ if (block_bit_len == 0 && node_bit_len == 0) {
+ block_bit_len =
+ prefix->prefixlen - ZEBRA_SRV6_LOCATOR_NODE_LENGTH;
+ node_bit_len = ZEBRA_SRV6_LOCATOR_NODE_LENGTH;
+ } else if (block_bit_len == 0) {
+ block_bit_len = prefix->prefixlen - node_bit_len;
+ } else if (node_bit_len == 0) {
+ node_bit_len = prefix->prefixlen - block_bit_len;
+ } else {
+ if (block_bit_len + node_bit_len != prefix->prefixlen) {
+ vty_out(vty,
+ "%% block-len + node-len must be equal to the selected prefix length %d\n",
+ prefix->prefixlen);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+ }
+
+ if (prefix->prefixlen + func_bit_len + 0 > 128) {
+ vty_out(vty,
+ "%% prefix-len + function-len + arg-len (%ld) cannot be greater than 128\n",
+ prefix->prefixlen + func_bit_len + 0);
+ return CMD_WARNING_CONFIG_FAILED;
+ }
/*
- * TODO(slankdev): please support variable node-bit-length.
- * In draft-ietf-bess-srv6-services-05#section-3.2.1.
- * Locator block length and Locator node length are defined.
- * Which are defined as "locator-len == block-len + node-len".
- * In current implementation, node bits length is hardcoded as 24.
- * It should be supported various val.
- *
- * Cisco IOS-XR support only following pattern.
- * (1) Teh locator length should be 64-bits long.
- * (2) The SID block portion (MSBs) cannot exceed 40 bits.
- * If this value is less than 40 bits,
- * user should use a pattern of zeros as a filler.
- * (3) The Node Id portion (LSBs) cannot exceed 24 bits.
+ * Currently, the SID transposition algorithm implemented in bgpd
+ * handles incorrectly the SRv6 locators with function length greater
+ * than 20 bits. To prevent issues, we currently limit the function
+ * length to 20 bits.
+ * This limit will be removed when the bgpd SID transposition is fixed.
*/
- locator->block_bits_length = prefix->prefixlen - 24;
- locator->node_bits_length = 24;
+ if (func_bit_len > 20) {
+ vty_out(vty,
+ "%% currently func_bit_len > 20 is not supported\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
+
+ locator->block_bits_length = block_bit_len;
+ locator->node_bits_length = node_bit_len;
locator->function_bits_length = func_bit_len;
locator->argument_bits_length = 0;
@@ -338,6 +372,38 @@ DEFPY (locator_prefix,
return CMD_SUCCESS;
}
+DEFPY (locator_behavior,
+ locator_behavior_cmd,
+ "[no] behavior usid",
+ NO_STR
+ "Configure SRv6 behavior\n"
+ "Specify SRv6 behavior uSID\n")
+{
+ VTY_DECLVAR_CONTEXT(srv6_locator, locator);
+
+ if (no && !CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID))
+ /* SRv6 locator uSID flag already unset, nothing to do */
+ return CMD_SUCCESS;
+
+ if (!no && CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID))
+ /* SRv6 locator uSID flag already set, nothing to do */
+ return CMD_SUCCESS;
+
+ /* Remove old locator from zclients */
+ zebra_notify_srv6_locator_delete(locator);
+
+ /* Set/Unset the SRV6_LOCATOR_USID */
+ if (no)
+ UNSET_FLAG(locator->flags, SRV6_LOCATOR_USID);
+ else
+ SET_FLAG(locator->flags, SRV6_LOCATOR_USID);
+
+ /* Notify the new locator to zclients */
+ zebra_notify_srv6_locator_add(locator);
+
+ return CMD_SUCCESS;
+}
+
static int zebra_sr_config(struct vty *vty)
{
struct zebra_srv6 *srv6 = zebra_srv6_get_default();
@@ -356,9 +422,20 @@ static int zebra_sr_config(struct vty *vty)
vty_out(vty, " locator %s\n", locator->name);
vty_out(vty, " prefix %s/%u", str,
locator->prefix.prefixlen);
+ if (locator->block_bits_length)
+ vty_out(vty, " block-len %u",
+ locator->block_bits_length);
+ if (locator->node_bits_length)
+ vty_out(vty, " node-len %u",
+ locator->node_bits_length);
if (locator->function_bits_length)
vty_out(vty, " func-bits %u",
locator->function_bits_length);
+ if (locator->argument_bits_length)
+ vty_out(vty, " arg-len %u",
+ locator->argument_bits_length);
+ if (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID))
+ vty_out(vty, " behavior usid");
vty_out(vty, "\n");
vty_out(vty, " exit\n");
vty_out(vty, " !\n");
@@ -395,6 +472,7 @@ void zebra_srv6_vty_init(void)
/* Command for configuration */
install_element(SRV6_LOC_NODE, &locator_prefix_cmd);
+ install_element(SRV6_LOC_NODE, &locator_behavior_cmd);
/* Command for operation */
install_element(VIEW_NODE, &show_srv6_locator_cmd);
diff --git a/zebra/zebra_srv6_vty.h b/zebra/zebra_srv6_vty.h
index 42d6aefa9..2f8b5048d 100644
--- a/zebra/zebra_srv6_vty.h
+++ b/zebra/zebra_srv6_vty.h
@@ -20,6 +20,10 @@
#ifndef _ZEBRA_SRV6_VTY_H
#define _ZEBRA_SRV6_VTY_H
+#define ZEBRA_SRV6_LOCATOR_BLOCK_LENGTH 40
+#define ZEBRA_SRV6_LOCATOR_NODE_LENGTH 24
+#define ZEBRA_SRV6_FUNCTION_LENGTH 16
+
extern void zebra_srv6_vty_init(void);
#endif /* _ZEBRA_SRV6_VTY_H */
diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c
index a2844ca95..c99aa2e8f 100644
--- a/zebra/zebra_vrf.c
+++ b/zebra/zebra_vrf.c
@@ -44,9 +44,7 @@
#include "zebra/zebra_vxlan.h"
#include "zebra/zebra_netns_notify.h"
#include "zebra/zebra_routemap.h"
-#ifndef VTYSH_EXTRACT_PL
#include "zebra/zebra_vrf_clippy.c"
-#endif
#include "zebra/table_manager.h"
static void zebra_vrf_table_create(struct zebra_vrf *zvrf, afi_t afi,
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 77922d2fc..6561ac95f 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -46,9 +46,7 @@
#include "lib/route_opaque.h"
#include "zebra/zebra_vxlan.h"
#include "zebra/zebra_evpn_mh.h"
-#ifndef VTYSH_EXTRACT_PL
#include "zebra/zebra_vty_clippy.c"
-#endif
#include "zebra/zserv.h"
#include "zebra/router-id.h"
#include "zebra/ipforward.h"
@@ -224,6 +222,9 @@ static char re_status_output_char(const struct route_entry *re,
&& CHECK_FLAG(re->flags, ZEBRA_FLAG_OFFLOAD_FAILED))
return 'o';
+ if (CHECK_FLAG(re->flags, ZEBRA_FLAG_OUTOFSYNC))
+ return 'd';
+
if (star_p)
return '*';
else
@@ -1534,6 +1535,12 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe)
vty_out(vty, "\n");
}
+ if (nhe->nhg.nhgr.buckets)
+ vty_out(vty,
+ " Buckets: %u Idle Timer: %u Unbalanced Timer: %u Unbalanced time: %" PRIu64 "\n",
+ nhe->nhg.nhgr.buckets, nhe->nhg.nhgr.idle_timer,
+ nhe->nhg.nhgr.unbalanced_timer,
+ nhe->nhg.nhgr.unbalanced_time);
}
static int show_nexthop_group_id_cmd_helper(struct vty *vty, uint32_t id)