]> git.proxmox.com Git - mirror_frr.git/commitdiff
Merge pull request #12081 from sworleys/EMM-upstream
authorDonatas Abraitis <donatas@opensourcerouting.org>
Thu, 17 Nov 2022 14:46:58 +0000 (16:46 +0200)
committerGitHub <noreply@github.com>
Thu, 17 Nov 2022 14:46:58 +0000 (16:46 +0200)
Rework of Various Handling in EVPN for Extended Mac Mobility

626 files changed:
.github/workflows/conflicts.yml [new file with mode: 0644]
Makefile.am
alpine/APKBUILD.in
babeld/babel_zebra.c
babeld/subdir.am
bfdd/bfdd_cli.c
bfdd/bfdd_vty.c
bfdd/subdir.am
bgpd/bgp_attr.c
bgpd/bgp_attr.h
bgpd/bgp_bmp.c
bgpd/bgp_community.h
bgpd/bgp_conditional_adv.c
bgpd/bgp_debug.c
bgpd/bgp_debug.h
bgpd/bgp_dump.c
bgpd/bgp_errors.c
bgpd/bgp_errors.h
bgpd/bgp_evpn.c
bgpd/bgp_evpn_private.h
bgpd/bgp_evpn_vty.c
bgpd/bgp_fsm.c
bgpd/bgp_fsm.h
bgpd/bgp_io.c
bgpd/bgp_labelpool.c
bgpd/bgp_mac.c
bgpd/bgp_memory.c
bgpd/bgp_memory.h
bgpd/bgp_mplsvpn.c
bgpd/bgp_mplsvpn.h
bgpd/bgp_network.c
bgpd/bgp_nht.c
bgpd/bgp_open.c
bgpd/bgp_open.h
bgpd/bgp_orr.c [new file with mode: 0644]
bgpd/bgp_orr.h [new file with mode: 0644]
bgpd/bgp_packet.c
bgpd/bgp_pbr.c
bgpd/bgp_regex.h
bgpd/bgp_route.c
bgpd/bgp_route.h
bgpd/bgp_routemap.c
bgpd/bgp_routemap_nb.c
bgpd/bgp_routemap_nb.h
bgpd/bgp_routemap_nb_config.c
bgpd/bgp_rpki.c
bgpd/bgp_table.h
bgpd/bgp_updgrp.c
bgpd/bgp_updgrp_adv.c
bgpd/bgp_updgrp_packet.c
bgpd/bgp_vty.c
bgpd/bgp_zebra.c
bgpd/bgpd.c
bgpd/bgpd.h
bgpd/rfapi/rfapi.c
bgpd/subdir.am
configure.ac
debian/frr.install
debian/frr.logrotate [deleted file]
debian/frr.pam
doc/developer/cli.rst
doc/developer/conf.py
doc/developer/vtysh.rst
doc/manpages/conf.py
doc/user/bgp.rst
doc/user/conf.py
doc/user/index.rst
doc/user/installation.rst
doc/user/isisd.rst
doc/user/nexthop_groups.rst [new file with mode: 0644]
doc/user/ospfd.rst
doc/user/pathd.rst
doc/user/pbr.rst
doc/user/pim.rst
doc/user/pimv6.rst
doc/user/routemap.rst
doc/user/sharp.rst
doc/user/subdir.am
doc/user/zebra.rst
docker/alpine/Dockerfile
eigrpd/eigrp_cli.c
eigrpd/eigrp_dump.c
eigrpd/eigrp_vty.c
eigrpd/subdir.am
grpc/subdir.am
include/linux/rtnetlink.h
include/linux/seg6_local.h
isisd/isis_adjacency.c
isisd/isis_adjacency.h
isisd/isis_circuit.c
isisd/isis_circuit.h
isisd/isis_cli.c
isisd/isis_lfa.c
isisd/isis_lsp.c
isisd/isis_lsp.h
isisd/isis_nb.c
isisd/isis_nb.h
isisd/isis_nb_config.c
isisd/isis_route.c
isisd/isis_route.h
isisd/isis_spf.c
isisd/isis_spf.h
isisd/isis_sr.c
isisd/isis_te.c
isisd/isisd.c
isisd/isisd.h
isisd/subdir.am
ldpd/ldp_vty_cmds.c
ldpd/neighbor.c
ldpd/subdir.am
lib/agentx.c
lib/command.c
lib/command.h
lib/command_graph.c
lib/command_graph.h
lib/command_match.c
lib/command_py.c
lib/filter_cli.c
lib/frrscript.c
lib/frrscript.h
lib/frrstr.c
lib/frrstr.h
lib/grammar_sandbox.c
lib/if.c
lib/if.h
lib/ipaddr.h
lib/libfrr.c
lib/linklist.c
lib/log_vty.c
lib/nexthop_group.c
lib/nexthop_group.h
lib/northbound_cli.c
lib/orr_msg.h [new file with mode: 0644]
lib/plist.c
lib/prefix.c
lib/prefix.h
lib/routemap.c
lib/routemap.h
lib/routemap_cli.c
lib/sockopt.c
lib/sockopt.h
lib/srv6.c
lib/srv6.h
lib/stream.h
lib/subdir.am
lib/thread.c
lib/vty.c
lib/vty.h
lib/zclient.c
lib/zclient.h
lib/zebra.h
lib/zlog_5424_cli.c
nhrpd/nhrp_vty.c
nhrpd/subdir.am
ospf6d/ospf6_area.c
ospf6d/ospf6_asbr.c
ospf6d/ospf6_gr.c
ospf6d/ospf6_gr_helper.c
ospf6d/ospf6_interface.c
ospf6d/ospf6_lsa.c
ospf6d/ospf6_nssa.c
ospf6d/ospf6_nssa.h
ospf6d/ospf6_route.c
ospf6d/ospf6_top.c
ospf6d/ospf6d.c
ospf6d/subdir.am
ospfclient/ospf_apiclient.c
ospfclient/ospf_apiclient.h
ospfclient/ospfclient.c
ospfclient/ospfclient.py
ospfd/ospf_abr.h
ospfd/ospf_api.c
ospfd/ospf_api.h
ospfd/ospf_apiserver.c
ospfd/ospf_dump.c
ospfd/ospf_dump.h
ospfd/ospf_flood.c
ospfd/ospf_gr.c
ospfd/ospf_interface.c
ospfd/ospf_ldp_sync.c
ospfd/ospf_lsa.c
ospfd/ospf_lsa.h
ospfd/ospf_lsdb.c
ospfd/ospf_memory.c
ospfd/ospf_memory.h
ospfd/ospf_opaque.c
ospfd/ospf_opaque.h
ospfd/ospf_orr.c [new file with mode: 0644]
ospfd/ospf_orr.h [new file with mode: 0644]
ospfd/ospf_packet.c
ospfd/ospf_route.c
ospfd/ospf_route.h
ospfd/ospf_spf.c
ospfd/ospf_spf.h
ospfd/ospf_vty.c
ospfd/ospf_zebra.c
ospfd/ospfd.c
ospfd/ospfd.h
ospfd/subdir.am
pathd/path_cli.c
pathd/path_pcep_cli.c
pathd/path_ted.c
pathd/path_ted.h
pathd/pathd.c
pathd/pathd.h
pathd/subdir.am
pbrd/pbr_debug.c
pbrd/pbr_main.c
pbrd/pbr_nht.c
pbrd/pbr_nht.h
pbrd/pbr_vty.c
pbrd/subdir.am
pceplib/pcep_msg_messages.c
pceplib/pcep_msg_messages_encoding.c
pceplib/pcep_pcc.c
pceplib/pcep_pcc_api.c
pceplib/pcep_session_logic.c
pceplib/pcep_socket_comm.c
pceplib/pcep_timers.c
pceplib/pcep_utils_double_linked_list.c
pceplib/pcep_utils_logging.c
pceplib/pcep_utils_memory.c
pceplib/pcep_utils_queue.c
pimd/pim6_cmd.c
pimd/pim6_cmd.h
pimd/pim6_mld.c
pimd/pim_br.c [deleted file]
pimd/pim_br.h [deleted file]
pimd/pim_cmd.c
pimd/pim_cmd_common.c
pimd/pim_cmd_common.h
pimd/pim_iface.c
pimd/pim_igmp_mtrace.c
pimd/pim_memory.c
pimd/pim_memory.h
pimd/pim_mroute.c
pimd/pim_mroute.h
pimd/pim_nb_config.c
pimd/pim_nht.c
pimd/pim_nht.h
pimd/pim_register.c
pimd/pim_rp.c
pimd/pim_rpf.c
pimd/pim_tib.c
pimd/pim_upstream.c
pimd/pim_util.c
pimd/pim_util.h
pimd/pim_vty.c
pimd/pim_zlookup.c
pimd/subdir.am
python/callgraph-dot.py
python/clippy/__init__.py
python/clippy/elf.py
python/clippy/uidhash.py
python/makefile.py
python/runtests.py
python/test_xrelfo.py
python/tiabwarfo.py
python/vtysh-cmd-check.py [deleted file]
python/xref2vtysh.py [new file with mode: 0644]
python/xrelfo.py
redhat/frr.pam
redhat/frr.spec.in
ripd/rip_cli.c
ripd/rip_debug.c
ripd/ripd.c
ripd/subdir.am
ripngd/ripng_cli.c
ripngd/ripng_debug.c
ripngd/ripngd.c
ripngd/subdir.am
sharpd/sharp_nht.c
sharpd/sharp_vty.c
sharpd/sharp_zebra.c
sharpd/subdir.am
snapcraft/snapcraft.yaml.in
staticd/static_main.c
staticd/static_vty.c
staticd/subdir.am
tests/isisd/test_isis_spf.refout
tests/topotests/all_protocol_startup/r1/ospf6d.conf
tests/topotests/all_protocol_startup/r1/ospfd.conf
tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post4.1.ref
tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post5.0.ref
tests/topotests/all_protocol_startup/r1/show_bgp_ipv4-post6.1.ref
tests/topotests/all_protocol_startup/r1/show_bgp_ipv4.ref
tests/topotests/all_protocol_startup/r1/show_bgp_ipv6-post4.1.ref
tests/topotests/all_protocol_startup/r1/show_bgp_ipv6.ref
tests/topotests/all_protocol_startup/r1/show_bgp_ipv6_post6.1.ref
tests/topotests/all_protocol_startup/r1/show_ip_ospf_interface.ref
tests/topotests/all_protocol_startup/test_all_protocol_startup.py
tests/topotests/bgp_accept_own/__init__.py [new file with mode: 0644]
tests/topotests/bgp_accept_own/ce1/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_accept_own/ce1/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_accept_own/ce2/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_accept_own/ce2/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_accept_own/pe1/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_accept_own/pe1/ldpd.conf [new file with mode: 0644]
tests/topotests/bgp_accept_own/pe1/ospfd.conf [new file with mode: 0644]
tests/topotests/bgp_accept_own/pe1/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_accept_own/rr1/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_accept_own/rr1/ldpd.conf [new file with mode: 0644]
tests/topotests/bgp_accept_own/rr1/ospfd.conf [new file with mode: 0644]
tests/topotests/bgp_accept_own/rr1/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_accept_own/test_bgp_accept_own.py [new file with mode: 0644]
tests/topotests/bgp_aigp/__init__.py [new file with mode: 0644]
tests/topotests/bgp_aigp/r1/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_aigp/r1/ospfd.conf [new file with mode: 0644]
tests/topotests/bgp_aigp/r1/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_aigp/r2/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_aigp/r2/ospfd.conf [new file with mode: 0644]
tests/topotests/bgp_aigp/r2/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_aigp/r3/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_aigp/r3/ospfd.conf [new file with mode: 0644]
tests/topotests/bgp_aigp/r3/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_aigp/r4/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_aigp/r4/ospfd.conf [new file with mode: 0644]
tests/topotests/bgp_aigp/r4/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_aigp/r5/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_aigp/r5/ospfd.conf [new file with mode: 0644]
tests/topotests/bgp_aigp/r5/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_aigp/r6/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_aigp/r6/ospfd.conf [new file with mode: 0644]
tests/topotests/bgp_aigp/r6/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_aigp/r7/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_aigp/r7/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_aigp/test_bgp_aigp.py [new file with mode: 0644]
tests/topotests/bgp_basic_functionality_topo1/test_bgp_basic_functionality.py
tests/topotests/bgp_communities_topo1/test_bgp_communities.py
tests/topotests/bgp_communities_topo1/test_bgp_communities_topo2.py
tests/topotests/bgp_conditional_advertisement_track_peer/__init__.py [new file with mode: 0644]
tests/topotests/bgp_conditional_advertisement_track_peer/r1/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_conditional_advertisement_track_peer/r1/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_conditional_advertisement_track_peer/r2/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_conditional_advertisement_track_peer/r2/staticd.conf [new file with mode: 0644]
tests/topotests/bgp_conditional_advertisement_track_peer/r2/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_conditional_advertisement_track_peer/r3/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_conditional_advertisement_track_peer/r3/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_conditional_advertisement_track_peer/test_bgp_conditional_advertisement_track_peer.py [new file with mode: 0644]
tests/topotests/bgp_ecmp_topo2/test_ebgp_ecmp_topo2.py
tests/topotests/bgp_ecmp_topo2/test_ibgp_ecmp_topo2.py
tests/topotests/bgp_ecmp_topo3/test_ibgp_ecmp_topo3.py
tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-1.py
tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-2.py
tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-3.py
tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-4.py
tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-1.py
tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-2.py
tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-3.py
tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-4.py
tests/topotests/bgp_gr_functionality_topo3/bgp_gr_functionality_topo3.py
tests/topotests/bgp_gr_restart_retain_routes/r2/zebra.conf
tests/topotests/bgp_gshut_topo1/test_ebgp_gshut_topo1.py
tests/topotests/bgp_gshut_topo1/test_ibgp_gshut_topo1.py
tests/topotests/bgp_local_asn/bgp_local_asn_agg.json [new file with mode: 0644]
tests/topotests/bgp_local_asn/bgp_local_asn_ecmp.json [new file with mode: 0644]
tests/topotests/bgp_local_asn/bgp_local_asn_topo1.json [new file with mode: 0644]
tests/topotests/bgp_local_asn/bgp_local_asn_topo2.json [new file with mode: 0644]
tests/topotests/bgp_local_asn/bgp_local_asn_vrf_topo1.json [new file with mode: 0644]
tests/topotests/bgp_local_asn/bgp_local_asn_vrf_topo2.json [new file with mode: 0644]
tests/topotests/bgp_local_asn/test_bgp_local_asn_agg.py [new file with mode: 0644]
tests/topotests/bgp_local_asn/test_bgp_local_asn_ecmp.py [new file with mode: 0644]
tests/topotests/bgp_local_asn/test_bgp_local_asn_topo1.py [new file with mode: 0644]
tests/topotests/bgp_local_asn/test_bgp_local_asn_topo2.py [new file with mode: 0644]
tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo1.py [new file with mode: 0644]
tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo2.py [new file with mode: 0644]
tests/topotests/bgp_max_med_on_startup/__init__.py [new file with mode: 0644]
tests/topotests/bgp_max_med_on_startup/r1/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_max_med_on_startup/r1/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_max_med_on_startup/r2/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_max_med_on_startup/r2/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_max_med_on_startup/test_bgp_max_med_on_startup.py [new file with mode: 0644]
tests/topotests/bgp_prefix_list_topo1/test_prefix_lists.py
tests/topotests/bgp_route_map/test_route_map_topo1.py
tests/topotests/bgp_route_map/test_route_map_topo2.py
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/zebra.conf
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/zebra.conf
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r1/zebra.conf
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/r2/zebra.conf
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce1/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce1/ip_rib.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce1/ipv6_rib.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce1/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce2/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce2/ip_rib.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce2/ipv6_rib.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce2/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce3/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce3/ip_rib.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce3/ipv6_rib.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce3/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce4/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce4/ip_rib.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce4/ipv6_rib.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce4/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce5/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce5/ip_rib.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce5/ipv6_rib.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce5/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce6/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce6/ip_rib.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce6/ipv6_rib.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/ce6/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv4_rib.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv4_rib_locator_deleted.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv4_rib_locator_recreated.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv4_rib_sid_vpn_export_disabled.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv4_rib_sid_vpn_export_reenabled.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv6_rib.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv6_rib_locator_deleted.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv6_rib_locator_recreated.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv6_rib_sid_vpn_export_disabled.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vpnv6_rib_sid_vpn_export_reenabled.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vrf10v4_rib.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vrf10v6_rib.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vrf20v4_rib.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/vrf20v6_rib.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r1/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/bgpd.conf [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv4_rib.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv4_rib_locator_deleted.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv4_rib_locator_recreated.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv4_rib_sid_vpn_export_disabled.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv4_rib_sid_vpn_export_reenabled.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv6_rib.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv6_rib_locator_deleted.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv6_rib_locator_recreated.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv6_rib_sid_vpn_export_disabled.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vpnv6_rib_sid_vpn_export_reenabled.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vrf10v4_rib.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vrf10v6_rib.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vrf20v4_rib.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/vrf20v6_rib.json [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/r2/zebra.conf [new file with mode: 0644]
tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py [new file with mode: 0644]
tests/topotests/bgp_suppress_fib/r1/bgp_ipv4_allowas.json
tests/topotests/bgp_suppress_fib/r2/bgp_ipv4_allowas.json
tests/topotests/bgp_suppress_fib/r2/bgpd.conf
tests/topotests/bgp_suppress_fib/r2/zebra.conf
tests/topotests/bgp_suppress_fib/r3/v4_route3.json [new file with mode: 0644]
tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py
tests/topotests/cspf_topo1/r1/zebra.conf
tests/topotests/cspf_topo1/r2/zebra.conf
tests/topotests/cspf_topo1/reference/sharp-ted.json
tests/topotests/cspf_topo1/test_cspf_topo1.py
tests/topotests/isis_lfa_topo1/rt1/bfdd.conf [new file with mode: 0644]
tests/topotests/isis_lfa_topo1/rt1/step14/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_lfa_topo1/rt1/step15/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_lfa_topo1/rt1/step16/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_lfa_topo1/rt2/bfdd.conf [new file with mode: 0644]
tests/topotests/isis_lfa_topo1/test_isis_lfa_topo1.py
tests/topotests/isis_te_topo1/r1/zebra.conf
tests/topotests/isis_te_topo1/r2/zebra.conf
tests/topotests/isis_te_topo1/reference/ted_step1.json
tests/topotests/isis_te_topo1/reference/ted_step2.json
tests/topotests/isis_te_topo1/reference/ted_step3.json
tests/topotests/isis_te_topo1/reference/ted_step4.json
tests/topotests/isis_te_topo1/reference/ted_step5.json
tests/topotests/isis_te_topo1/reference/ted_step6.json
tests/topotests/isis_tilfa_topo1/rt1/step10/show_ip_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt1/step10/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt1/step10/show_mpls_table.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt1/step11/show_ip_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt1/step11/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt1/step11/show_mpls_table.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt1/step12/show_ip_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt1/step12/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt1/step12/show_mpls_table.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt2/step10/show_ip_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt2/step10/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt2/step10/show_mpls_table.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt2/step11/show_ip_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt2/step11/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt2/step11/show_mpls_table.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt2/step12/show_ip_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt2/step12/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt2/step12/show_mpls_table.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt3/step10/show_ip_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt3/step10/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt3/step10/show_mpls_table.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt3/step11/show_ip_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt3/step11/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt3/step11/show_mpls_table.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt3/step12/show_ip_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt3/step12/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt3/step12/show_mpls_table.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt4/step10/show_ip_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt4/step10/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt4/step10/show_mpls_table.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt4/step11/show_ip_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt4/step11/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt4/step11/show_mpls_table.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt4/step12/show_ip_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt4/step12/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt4/step12/show_mpls_table.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt5/bfdd.conf [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt5/step10/show_ip_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt5/step10/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt5/step10/show_mpls_table.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt5/step11/show_ip_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt5/step11/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt5/step11/show_mpls_table.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt5/step12/show_ip_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt5/step12/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt5/step12/show_mpls_table.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt6/bfdd.conf [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt6/step10/show_ip_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt6/step10/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt6/step10/show_mpls_table.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt6/step11/show_ip_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt6/step11/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt6/step11/show_mpls_table.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt6/step12/show_ip_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt6/step12/show_ipv6_route.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/rt6/step12/show_mpls_table.ref.diff [new file with mode: 0644]
tests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py
tests/topotests/isis_topo1/test_isis_topo1.py
tests/topotests/lib/bgp.py
tests/topotests/lib/common_config.py
tests/topotests/lib/pim.py
tests/topotests/multicast_pim6_static_rp_topo1/__init__.py [new file with mode: 0644]
tests/topotests/multicast_pim6_static_rp_topo1/multicast_pim6_static_rp.json [new file with mode: 0644]
tests/topotests/multicast_pim6_static_rp_topo1/test_multicast_pim6_static_rp1.py [new file with mode: 0755]
tests/topotests/multicast_pim6_static_rp_topo1/test_multicast_pim6_static_rp2.py [new file with mode: 0755]
tests/topotests/multicast_pim_static_rp_topo1/multicast_pimv6_static_rp.json [deleted file]
tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pimv6_static_rp.py [deleted file]
tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py
tests/topotests/ospf_te_topo1/r1/zebra.conf
tests/topotests/ospf_te_topo1/r2/zebra.conf
tests/topotests/ospf_te_topo1/reference/ted_step1.json
tests/topotests/ospf_te_topo1/reference/ted_step2.json
tests/topotests/ospf_te_topo1/reference/ted_step3.json
tests/topotests/ospf_te_topo1/reference/ted_step4.json
tests/topotests/ospf_te_topo1/reference/ted_step5.json
tests/topotests/ospf_te_topo1/reference/ted_step6.json
tests/topotests/ospf_te_topo1/reference/ted_step7.json
tests/topotests/ospfapi/test_ospf_clientapi.py
tests/topotests/pytest.ini
tests/topotests/srv6_locator_custom_bits_length/__init__.py [new file with mode: 0644]
tests/topotests/srv6_locator_custom_bits_length/expected_chunks1.json [new file with mode: 0644]
tests/topotests/srv6_locator_custom_bits_length/expected_chunks2.json [new file with mode: 0644]
tests/topotests/srv6_locator_custom_bits_length/expected_chunks3.json [new file with mode: 0644]
tests/topotests/srv6_locator_custom_bits_length/expected_chunks4.json [new file with mode: 0644]
tests/topotests/srv6_locator_custom_bits_length/expected_chunks5.json [new file with mode: 0644]
tests/topotests/srv6_locator_custom_bits_length/expected_chunks6.json [new file with mode: 0644]
tests/topotests/srv6_locator_custom_bits_length/expected_locators1.json [new file with mode: 0644]
tests/topotests/srv6_locator_custom_bits_length/expected_locators2.json [new file with mode: 0644]
tests/topotests/srv6_locator_custom_bits_length/expected_locators3.json [new file with mode: 0644]
tests/topotests/srv6_locator_custom_bits_length/expected_locators4.json [new file with mode: 0644]
tests/topotests/srv6_locator_custom_bits_length/expected_locators5.json [new file with mode: 0644]
tests/topotests/srv6_locator_custom_bits_length/expected_locators6.json [new file with mode: 0644]
tests/topotests/srv6_locator_custom_bits_length/r1/setup.sh [new file with mode: 0644]
tests/topotests/srv6_locator_custom_bits_length/r1/sharpd.conf [new file with mode: 0644]
tests/topotests/srv6_locator_custom_bits_length/r1/zebra.conf [new file with mode: 0644]
tests/topotests/srv6_locator_custom_bits_length/test_srv6_locator.py [new file with mode: 0755]
tests/topotests/srv6_locator_usid/__init__.py [new file with mode: 0644]
tests/topotests/srv6_locator_usid/expected_chunks_1.json [new file with mode: 0644]
tests/topotests/srv6_locator_usid/expected_chunks_2.json [new file with mode: 0644]
tests/topotests/srv6_locator_usid/expected_chunks_3.json [new file with mode: 0644]
tests/topotests/srv6_locator_usid/expected_chunks_4.json [new file with mode: 0644]
tests/topotests/srv6_locator_usid/expected_chunks_5.json [new file with mode: 0644]
tests/topotests/srv6_locator_usid/expected_chunks_6.json [new file with mode: 0644]
tests/topotests/srv6_locator_usid/expected_chunks_7.json [new file with mode: 0644]
tests/topotests/srv6_locator_usid/expected_chunks_8.json [new file with mode: 0644]
tests/topotests/srv6_locator_usid/expected_locators_1.json [new file with mode: 0644]
tests/topotests/srv6_locator_usid/expected_locators_2.json [new file with mode: 0644]
tests/topotests/srv6_locator_usid/expected_locators_3.json [new file with mode: 0644]
tests/topotests/srv6_locator_usid/expected_locators_4.json [new file with mode: 0644]
tests/topotests/srv6_locator_usid/expected_locators_5.json [new file with mode: 0644]
tests/topotests/srv6_locator_usid/expected_locators_6.json [new file with mode: 0644]
tests/topotests/srv6_locator_usid/expected_locators_7.json [new file with mode: 0644]
tests/topotests/srv6_locator_usid/expected_locators_8.json [new file with mode: 0644]
tests/topotests/srv6_locator_usid/r1/setup.sh [new file with mode: 0644]
tests/topotests/srv6_locator_usid/r1/sharpd.conf [new file with mode: 0644]
tests/topotests/srv6_locator_usid/r1/zebra.conf [new file with mode: 0644]
tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py [new file with mode: 0755]
tests/topotests/zebra_seg6local_route/r1/routes.json
tests/topotests/zebra_seg6local_route/r1/setup.sh
tests/topotests/zebra_seg6local_route/test_zebra_seg6local_route.py
tools/etc/frr/support_bundle_commands.conf
tools/etc/logrotate.d/frr [new file with mode: 0644]
tools/frr-reload.py
tools/frr.in
tools/frrcommon.sh.in
tools/frrinit.sh.in
tools/permutations.c
vrrpd/subdir.am
vrrpd/vrrp_vty.c
vtysh/.gitignore
vtysh/extract.pl.in [deleted file]
vtysh/subdir.am
vtysh/vtysh.c
vtysh/vtysh_config.c
watchfrr/subdir.am
watchfrr/watchfrr.c
watchfrr/watchfrr_vty.c
yang/frr-bgp-route-map.yang
yang/frr-isisd.yang
zebra/debug.c
zebra/dpdk/zebra_dplane_dpdk_vty.c
zebra/dplane_fpm_nl.c
zebra/interface.c
zebra/main.c
zebra/netconf_netlink.c
zebra/rib.h
zebra/rt_netlink.c
zebra/rtadv.c
zebra/subdir.am
zebra/tc_netlink.c
zebra/zapi_msg.c
zebra/zebra_evpn_mh.c
zebra/zebra_fpm.c
zebra/zebra_mlag_vty.c
zebra/zebra_nhg.c
zebra/zebra_nhg.h
zebra/zebra_rib.c
zebra/zebra_routemap.c
zebra/zebra_srte.c
zebra/zebra_srte.h
zebra/zebra_srv6.c
zebra/zebra_srv6.h
zebra/zebra_srv6_vty.c
zebra/zebra_srv6_vty.h
zebra/zebra_vrf.c
zebra/zebra_vty.c

diff --git a/.github/workflows/conflicts.yml b/.github/workflows/conflicts.yml
new file mode 100644 (file)
index 0000000..18a8c0d
--- /dev/null
@@ -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."
index ce0f70a1a294043f17f989b15b75cdb80f5ce760..44d2ab8e72b80d5533430df61f62ebb726519528 100644 (file)
@@ -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 \
        \
index 51986de2dd2af1a92c6e94c373ef43225b77994b..3aad9549b5fb07f72c7d22b707897e73f738aa01 100644 (file)
@@ -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() {
index d0da93e50747d0fd972c5dea2ccc4991f68b0d89..daaa870a646a700959f0fa11c4e84b9adcdbaa84 100644 (file)
@@ -225,6 +225,8 @@ DEFUN_NOSH (show_debugging_babel,
 
        debug_babel_config_write(vty);
 
+       cmd_show_lib_debugs(vty);
+
        return CMD_SUCCESS;
 }
 
index 856cbd13e397582b2e3435c8b64fef652a9c5ac6..4b9037283c5d29e7cfad113709fe23035dddb323 100644 (file)
@@ -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
 
index 69424c45d9a8d5220c830271d83169c73aeef924..52f2dd8fd32553649faf1a0eb05ce823c53c4996 100644 (file)
@@ -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"
index 21429f06cfbf269c4630bd38d4c527a80089d794..7b7a001e24b2f510376fae6b106ccc3cf214776d 100644 (file)
@@ -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;
 }
 
index 8d35b933d789bf399d823de460c752b7dd5d57f3..b86a18967e19095c5a679634d86f391d2ec0d01a 100644 (file)
@@ -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
index b7d0958bac02b3e10140061ef95a3618f67f74d9..89aed1ba699fde82b55996e6ac68ac750cb4167d 100644 (file)
@@ -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);
index 4963ea64d093edc155ea260ff753edbf215734c7..bc82d0c6ed6976b19aa716a1eb925d8ab1c585e7 100644 (file)
 #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;
index bcab4099c049442ab8d338ed423e8da9f2d41da9..2a65dbac804dd72dd6b4f758a35151a655aec523 100644 (file)
@@ -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,
index 616ddb4405b371228e4797558313e1c7b4a505c4..05a5d4486a0a95c74fce9cbde0466006270e5dc2 100644 (file)
@@ -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 */
index 2598361ad2c584fa924d5349febc0aac80fac9a6..4ad00ed121bb2fcb9fa51c09f3a4b912f81006e3 100644 (file)
@@ -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)) {
index df7262be6412e590747bf6daae4ad8bd208f167e..92a22d71b319220fb1943a3f9dbce3387499ba14 100644 (file)
@@ -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
index be5ed0afdc8d0f8178c13ce33205cebabdcdfa04..f7090260ac395095baebf58481404c85c302e94f 100644 (file)
@@ -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
index 11e84f00b4d04c36954f6f52594d5618d90b97fd..254996edadd63e1ce424009026965a73222f8fd0 100644 (file)
@@ -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
index 9f87f8ce7a6fcf382e9621c628f421269978e250..8bc2dbca7a2273edf11f8868d0ff926c4d56f7be 100644 (file)
@@ -235,6 +235,12 @@ static struct log_ref ferr_bgp_err[] = {
                .description = "BGP update has invalid length for PMSI tunnel",
                .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",
index 0c0917c49e9606e7827923cf3ff9a92fff240115..4986c314a182498a652c90f57cd569eaae73a363 100644 (file)
@@ -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,
index 90e04a042d2837eab227e2e74c98383bb36cd7a4..eab70bfdafbfb7255c4de3407230a36cb85ad808 100644 (file)
@@ -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,18 +350,53 @@ 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;
        ecommunity_free(&ecomm);
 }
 
+/*
+ * 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.
index eb78a755db0c02b5bb6d701bc1de47ccfda3aa26..3f18e4e9f1d7822071459bdaad465cbd26c12ba7 100644 (file)
@@ -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);
index 12fe65c72b20d87ba07c6f9f1f5a8cf1b35b03cf..88c1329f48e0c342c96d2a4d3729c1861d8ae143 100644 (file)
@@ -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);
index ddda10077456bfc11094932a1b27519b92a053d2..f110005e49f28d3b05c900719c8709534f3880d0 100644 (file)
@@ -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;
index aaf6c480b2400b237b81b3825b75d1c260f84b14..368c2c5001621468629067a555c3ce83c128f7f5 100644 (file)
@@ -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 */
index f9bb8d518d960404f5765007a1aea056b4ef9db4..49ae9816a32a54fc759f12c177643115be900796 100644 (file)
@@ -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 */
index c227a5e41c403b2bd206d2f445546eeb65a6e734..129878451d3f915c10325f7efcf319cf4f1a46b5 100644 (file)
@@ -39,9 +39,7 @@
 
 #define BGP_LABELPOOL_ENABLE_TESTS 0
 
-#ifndef VTYSH_EXTRACT_PL
 #include "bgpd/bgp_labelpool_clippy.c"
-#endif
 
 
 /*
index 02b7e648697c6e6209a97e02fa1ca993c012a887..b9649ac4da0e643b05b39289286a7aac7ca07362 100644 (file)
@@ -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);
                }
        }
index 850657d35ed0c730d57298c45ab712baf17ef711..ced3e1890e0d57279b2ed818fe190545d089a23a 100644 (file)
@@ -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");
index 510cfa21c9217913f0459c09d61c43cd80be8279..990c6e1faaec9908e2c83b88ab98074fd3a25299 100644 (file)
@@ -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 */
index d7fd4bc77e0c818925d00907275d93fbd6b821a5..18cb90763c038a91062982b9023bf76e3ce96d34 100644 (file)
@@ -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)
@@ -405,11 +403,78 @@ void vpn_leak_zebra_vrf_sid_update(struct bgp *bgp, afi_t afi)
        bgp->vpn_policy[afi].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.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);
                        }
                }
        }
index c5cc7d42949f5688a8c9de0ec25424b059a570d3..7b57e4c75d1064cedeb2bb5a2ffa32d69d2bed10 100644 (file)
@@ -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);
index 9ecc2ae4e42667a9c08a37bcc936ae3037f181d5..9582ec01ed757a9edef1d78c71ccf84365eb80f3 100644 (file)
@@ -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;
        }
 
index 7274bcdb21db07c183730e0df397188d7c3f9c7d..fd1aa6ab47c079715eda396247a8fe02ab28a925 100644 (file)
@@ -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);
 }
 
 
index d1667fac2612f1a3b8e634d2789284cdc1013773..c8cb6b77e2754ef196270e4451b2cdab5e86215d 100644 (file)
@@ -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:
index 19ddd9bd25afed6a9019ae1df3edb3e83cc8be69..6be94443c80f818ea0a1b0d102d2497469700f85 100644 (file)
@@ -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 (file)
index 0000000..7fed6b7
--- /dev/null
@@ -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 (file)
index 0000000..158de30
--- /dev/null
@@ -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 */
index 8ae31bf2e695ac56044428435322f9210ed9cf38..f3ca3bba0a0651299f63bed039b01a011cd735e6 100644 (file)
@@ -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 {
index 7b5e28724209573662a4ff020bbf871a156eb25c..b71e19ab330f7ae0b6321448aed9201fcf1fe207 100644 (file)
@@ -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(
index 43ebb9ac918f5d65515a925aaecaeeecb67d2ef9..e07b7f911b9e09c114942b52bfad3c7c7fa29f77 100644 (file)
  * 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 */
index 61976834f4b7f90953dd8cc988a4ac0a99e5d725..6eb1a556b1f635fdc4b0246c9b86b002b6e9e129 100644 (file)
@@ -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,
index 1b04bfc713db5a107263541b2f4441c231ff0026..3fa58c0dfb6904bebbfc4c17cdd2b504b1f7bee3 100644 (file)
@@ -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 */
index ded47028a69e951a70e946ec4a5c8d2744d40b3a..b736e6c38a97dd11d9760632a157057d82af4c7f 100644 (file)
 #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.
 
@@ -642,6 +645,20 @@ route_match_prefix_list_flowspec(afi_t afi, struct prefix_list *plist,
        return RMAP_NOMATCH;
 }
 
+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);
index c47c37dc667bc3fc87df1c4cfcb91a10d42e061d..35e470349275dff7ae122e253bb36cca759e79b8 100644 (file)
@@ -282,6 +282,13 @@ const struct frr_yang_module_info frr_bgp_route_map_info = {
                                .destroy = 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",
+                       .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 = {
index 163e3b55cc0de19a1e32ffd39407a8217afcace8..93320441585954a2eeaf6caa879f497d3c541a3a 100644 (file)
@@ -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);
index b18cf9d4ddfe00537728062dd32b54326c683084..216bcc0b07de15d917a2cc8bc7b1d31b75ce5701 100644 (file)
@@ -2088,6 +2088,58 @@ lib_route_map_entry_set_action_rmap_set_action_atomic_aggregate_destroy(
        return NB_OK;
 }
 
+/*
+ * 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
index b90c09c68b2175620a3f4ff386f54e8d2ee82263..73c6fe0c4757fa27549e850a7822dfe38eaf17e9 100644 (file)
 
 #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);
 }
 
index 86cd4f3da105add288fe36d4fe8dd0feeb8ead52..121afc481fe5cbd4272f24892a87a99b643d0ba7 100644 (file)
@@ -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,
index 0219535b0d57b567959148d08b27ff5e691c6399..9d550fd19b826e555d3eaed8dcfcd1637e923ae1 100644 (file)
@@ -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]);
 
index 27e3677702ef35938f62e5a12fa81e9923090685..72e70ebf9fa82b50dd1ba8f396b1703c4e31a48f 100644 (file)
@@ -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);
        }
 
index 88a81f255de86d0afbf982f1f606a8ebc6e9a7cb..9de97cf06003221d899aa7e8acd324adf7fd0055 100644 (file)
@@ -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);
index 5b4a56233df87503488697afec441086727799d2..6f0bd5ededfda591546ddc66fbaeceeb117a09ad 100644 (file)
@@ -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();
 }
index 57a859c61da9a803026448e894a772655d6adc1c..efdc81a14503920631d491ba06810fafbe0594c7 100644 (file)
 #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;
+}
index 5a9ec1bbdc7551c2b9464ff526d86aff234c62b9..6ad1cf2c06f150c05f88d672ce555ff8db90b378 100644 (file)
@@ -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.
index c8bcb5cd555b320995b7deef78c02500e43fbc6c..8a0ec5ad2d3f1003da844979dc3ebac7037f0301 100644 (file)
@@ -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);
index ed0714ce2d929ff41677a2cb1d036befdd43da87..a5d57748b71ac0592d5f7a8be804c4608613caa4 100644 (file)
@@ -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
         */
index b1eeb937e180b0cc5ec607392763489c332fa893..04fe1f12491cc4393db4779d36b5f8f191e481ca 100644 (file)
@@ -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 \
index 4e1080045e7890e50ac3b300fcdf6ba8b40a2834..97c8ca451b80639f88ae75ff0ddbec7ebac8387f 100644 (file)
@@ -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])
index 48263222f82b958e19f1d7a6e181edca45fbfafb..044b48498458079cb46b7422844f7ea4229b30e6 100644 (file)
@@ -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.logrotate b/debian/frr.logrotate
deleted file mode 100644 (file)
index 735af65..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/var/log/frr/*.log {
-        size 500k
-        sharedscripts
-        missingok
-        compress
-        rotate 14
-        create 0640 frr frr
-
-        postrotate
-            pid=$(lsof -t -a -c /syslog/ /var/log/frr/* 2>/dev/null)
-            if [ -n "$pid" ]
-            then # using syslog
-                 kill -HUP $pid
-            fi
-            # in case using file logging; if switching back and forth
-            # between file and syslog, rsyslogd might still have file
-            # open, as well as the daemons, so always signal the daemons.
-            # It's safe, a NOP if (only) syslog is being used.
-            for i in babeld bgpd eigrpd isisd ldpd nhrpd ospf6d ospfd sharpd \
-                pimd pim6d ripd ripngd zebra pathd pbrd staticd bfdd fabricd vrrpd; do
-                if [ -e /var/run/frr/$i.pid ] ; then
-                    pids="$pids $(cat /var/run/frr/$i.pid)"
-                fi
-            done
-            [ -n "$pids" ] && kill -USR1 $pids || true
-        endscript
-}
index 2b106d43bc59429de22eb434f245c39b6ee5223c..737b88953b59373411b11f019ae3904d9bc176ea 100644 (file)
@@ -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
index ff6c4f6e16a1f0f8914a336283348085f0622372..d51f06d118f8debf14ecd974d747190232da8ba4 100644 (file)
@@ -453,9 +453,7 @@ all DEFPY statements**:
    /* GPL header */
    #include ...
    ...
-   #ifndef VTYSH_EXTRACT_PL
    #include "daemon/filename_clippy.c"
-   #endif
 
    DEFPY(...)
    DEFPY(...)
index 79f8233978aedc52e083e97837a221f23c390cff..495c604ae091b62e099170e7220379a8473f8bac 100644 (file)
@@ -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 = ''
index 160676a7b1f7eb7c909f282940316fae11945c58..323ea57c166d33a637e2d20500c98858501fa3b1 100644 (file)
@@ -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
index 186f7932b21de75377d783f0dafeb54377c08a23..73dea094ae9f916f8a04e237de25e2c004866d90 100644 (file)
@@ -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 = ''
index da3718fce2b1109028747d896dd156748ff4f7b5..44349976f6875948a398e7dcbb2c329e4cc25cc2 100644 (file)
@@ -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
index 6db58b07c317e8283ececa77469e4561b2801b67..728f9c936486b3affc78edd4c18d22f26c6f834c 100644 (file)
@@ -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 = ''
index 5a018a55835f19a21bcd0782031e384741f17005..c8ad85c0c792a95a56e80b6d34c3c319203e5816 100644 (file)
@@ -31,6 +31,7 @@ Basics
    kernel
    snmp
    scripting
+   nexthop_groups
 .. modules
 
 #########
index ba35facf2a881393a1c7e9e87fb19e65daf7eae4..8f89c6c4f828d07755c9ac78a1d204151b631fd3 100644 (file)
@@ -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].
index 9ccb5ba4b5b86518691258fd6c32662393c107c4..2b114ad127f58c1d6c6d387d8a85c944b17c16bd 100644 (file)
@@ -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 (file)
index 0000000..45f64ee
--- /dev/null
@@ -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.
index 26810bd8830de88566c785bf3651b2e4376f8d2c..181a6b2f3682f4dba16c8c3cac8428a023c55de6 100644 (file)
@@ -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
index f0b76f10b7a1197c3925fca6c142ff12cd20a8da..ec107fbe47253356dbe7519141db441c04720fdf 100644 (file)
@@ -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
 ----------------------
index 29567bb709f6a989e06a74c8f5f60f622f68689a..0cdb206dd55217fbe42c834d7bb5e482e94fb95e 100644 (file)
@@ -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
index 44ade916a2227869dd42ba815e852686a9120c40..5d849c7b8a17c953393386e3aa2681de0b8c4600 100644 (file)
@@ -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]
 
index b242f4fe17395ac30554c7d1eb8caaf67b87af8e..7fd285600192f8c3f72a751ca246d8010a200a78 100644 (file)
@@ -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.
index 5e222576ca3519d5eebb6d8f506855a94689cf35..c205122b0b98f5ea0fd8929eec5bc692c2745d03 100644 (file)
@@ -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.
index 8d201a3c06f19dceaadbffb6a1bac9144319d581..3e73a599edec56833c4d44d6639e0f996cdc7f81 100644 (file)
@@ -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
 
index 14ace2c8567168822a2c3b7b2fdcc59a5efb8065..825938b31c6c134edff1f63b8297ac1135526b6e 100644 (file)
@@ -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 \
index 05990e2523d1f3be77c0414d5460ea2110d07ce3..db43266d68bef9d861d7082d998720eca5dfb208 100644 (file)
@@ -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
 
index b9278dbb880e58f64e2360be3ae5e70defd3c0fe..238a7fc4097e280d134fc9a06b791e666496e474 100644 (file)
@@ -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 \
index 744f5f9c7ae27949a43f8ac1512e0dd01a8ac86a..2afd9d5eaaf6242766d3f18722a28dcd72195c75 100644 (file)
@@ -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
index e1ad51a9dbb1f7d4350accd2788e75a4310e8601..b0d34f55e619ccf2c917edef02a16df6ac0aa706 100644 (file)
@@ -322,6 +322,7 @@ DEFUN_NOSH (show_debugging_eigrp,
                }
        }
 
+       cmd_show_lib_debugs(vty);
        return CMD_SUCCESS;
 }
 
index 3d61294b22bd9989f8be7ef7c5ac99e56dd7fb80..137f9b028c59e14ee238cbb2281ab18469793127 100644 (file)
@@ -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,
index 3b647e060b842a9731df6bb41b196c89a6752f2b..e417132b51b35b6333097c905cff17dcf6f58753 100644 (file)
@@ -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
index cbebd72323d5e979a7ff8009f8fd42b191f59988..06b37f91d611ec773fdc48f595dc75d92879b6bd 100644 (file)
@@ -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:
index 71ad7bf69e1064e83ee73ba9b358cf4582181c80..d03ed4d16e35168516111fb6f4db302cd99b90d6 100644 (file)
@@ -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,
index bb5c8ddfcec52f06412fc7aedf69ef360698fc2f..ab724498aa94f3d29b601ed0e2b7b4dad651cfee 100644 (file)
@@ -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
index 00763135e69e28912ce6742bf7fc3874988ba87e..0957c897e6caa64b7a687010fe3a5fb66f6ebdfd 100644 (file)
@@ -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);
 
index 7467a619cb16c7dc102aac9cd400c69c9221149d..49adc89ae599e6eaff06c6187c9b277799e8559d 100644 (file)
@@ -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 */
index dcc4ed6e42f52297916c1175edf28ca95bee5e38..fa0f2c998f2f63ecd62e9c6962044ebd9eea9d50 100644 (file)
@@ -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);
index 5ff0390c26bf1fed78935430e4813f60211d747d..b3ad3f7ffe492229d2ec3e5c4bc25378c631fb25 100644 (file)
@@ -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,
index a673cb8c1ed4e4691feca3c2514f20a809b80055..3650984f1bb749fba6c803cafe0e37645e7abb4e 100644 (file)
@@ -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);
@@ -418,6 +416,42 @@ void cli_show_isis_overload(struct vty *vty, const struct lyd_node *dnode,
        vty_out(vty, " set-overload-bit\n");
 }
 
+/*
+ * 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
  */
@@ -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);
 
index c4fadcba0372fc12d8612b73bc7ea5b2d2016a4e..2ec6dafd3f0af86d2ccd1b7eb56011f32c873f55 100644 (file)
@@ -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,
index 5387f37039016ae8be149b4b7df407da9798ea32..63b4edb1e191a167139e4232280bf327d1f469a5 100644 (file)
@@ -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);
 }
index b13b2a35e6b0c6bedd0d7f85ef328a28cbf7d52f..d7762324d982e5fd740b271c7b5fdbfbb9c0d7d2 100644 (file)
@@ -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) \
index a2ba33d0782ac1cba7c910371f7fa97f2e098f6b..4f4e6dc730c81905056579fd727f6cd77cf48118 100644 (file)
@@ -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",
index 00ca8be3b0518bfe74561d2f0efc5b29f2b687a5..a9f2eaea95d5a204f67fcaaca0910d69774236a6 100644 (file)
@@ -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,
index e0decf48f2447157517f1b2473fed38b47a4a03c..1b7663fcfd8857afebbd2bd9b0fc18b16ea6aca5 100644 (file)
@@ -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,11 +348,31 @@ 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
  */
index 9f8f639e5d2e6fbc1d9390491b1fb1c5f04bb6f9..c7dc9b7c440111183a111bf0add0e6fe00805adc 100644 (file)
@@ -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);
+       }
+}
index 0e206d08f419bc80fd504eb986dad2cc02805a0d..a0e0500aecbb9bc30c75869e1b6ee8cdff426492 100644 (file)
@@ -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 */
index bdd323e1a7735077935b2528dbf7cf23d8e89bb0..0d1a5db0d691ae0cc1a030e84d21a3ef9bc8c1d6 100644 (file)
@@ -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);
        }
 
index 815db7b226a8e1297d7e9e5a13eec75e547a5736..3fa5182bafdd0dddb74489ac9ae9ec6d3fc9cc50 100644 (file)
@@ -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);
index f70840a637577db4aad55e19f262685972957e2c..707bd162f5ec18f48018f304d3b8c733971a0e41 100644 (file)
@@ -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")
 {
index 0093279cde362e3d8f636230c37a35f449104848..155d1e6fed5a1d60923b369211dc5a1d68215b6e 100644 (file)
@@ -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;
index 54e6be5970e7809aedd1ab6499193697af83754f..cd085254716efcf3c46d68d6604fe9ac816169d5 100644 (file)
@@ -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)
 {
 
index 4951e5809b79027a124d630a3ebcdfccb3bd7381..38f20b21135bfda3cc4ab1169b1330ef9ec20735 100644 (file)
@@ -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"
index 3e5816c16b9a04156f71ff05b29a6a4e92d0f0dc..dabf6a925ea0551ae3bf22794154d5ead3a2796c 100644 (file)
@@ -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
 
index 11d6930f06a30d65d49c52031062270796300303..33e6b297cbfab48cf38f65d4c4d86d3f37faf17a 100644 (file)
@@ -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
index e1db9e8e1e00f5a28b827c4c3e038eeedd6095f3..6d6c7d00cdb1f3311eae876732eb9b098cfe94a5 100644 (file)
@@ -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));
 }
index 083effb703ad80831de2816f951cdf9addff6193..0b948adb6fc21bb7b6b07bc8677b2650a018492a 100644 (file)
@@ -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
index 4c087219cb7e331132baefdc13f33a31906e0ebb..6c2923fcf8390f20c6cd59dae9a6c55ca8879a6d 100644 (file)
@@ -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();
index a23afb1e43863e15ff36c50a1d866ff1e69ca0f5..1fae32a04a3d299349448da8d12f972aed7199b6 100644 (file)
@@ -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);
index b701d4d0e9faab5105cb22c02c776a44b67b17aa..0f9715e81c1ca8c472d6ef6ea613734e0a4f64db 100644 (file)
@@ -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
index 09d802e796705b4e1003b0b804559148d68cbdc0..e940685250fad5343f9a670646913dfcaa963ca8 100644 (file)
@@ -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)
index ed4da6aa4c8942de03634eaa86111155793d3c1b..b8c7a9c72cc7f260f392f7ac863417940afb420d 100644 (file)
@@ -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 {
index f221e0a02ce7ebfc846d93b81dab1a5a0d0de85d..ce2dbc9528997ad5997146baaaebd77ee429896b 100644 (file)
@@ -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);
index 6301eec5e8ee1c6ee2604125bdccc79e222fc962..cce9542e303cce766ac5d589fd4c8889df8360a3 100644 (file)
@@ -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);
index 9a877a57041d8778ac0b6ad1ad7fd53cb8b68385..e0f0f177e51632aad99c7361971bd018115b4c18 100644 (file)
@@ -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"
index a19bd0c3dba54ac81c5e2db051f687173c48579c..2e56932613261fe69e7245965f34ecf950978557 100644 (file)
@@ -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 */
index 4db3e6f1b2260907a001196ee6877d4546df9d9c..7fa01f70d1baf861c0a3b819c6e37f84f2b4f5ee 100644 (file)
@@ -161,6 +161,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
index 1b98b224cc9e329d0fad8adbec15d2662feac4dc..d66c6f8c16f71ba049f7e074397b478e1cf4724e 100644 (file)
 #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"
index d52d6a4482293440a758ea12f3abb5deb29342e8..f0066d0fc5e8564f77e68874d4d058d955226b96 100644 (file)
 
 #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"
index f9778c5d4c460f068099f4c545e3a6ac9970772a..8fa47c053bcfaaa7d82ea9590b59c2291c9bf5fd 100644 (file)
@@ -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);
index fa4fdb82d38af2f01bba2717f256af4e1a7d0a91..76568071ef842bc7c6d97f06f7b9e50593478153 100644 (file)
--- 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);
index 1c948b875a458a6e178f087042ef70eb3d8aa80a..91dcd462474f5d567d28e972d36b617bebf5f19e 100644 (file)
--- 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. */
index d7ab358afea794f45f7fd207c79386eded772df9..43b3028200c7e9c71d0a81497833b2cac61a7d61 100644 (file)
@@ -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) {
index f5aecd9f75a3ec4c14260661a94cb56a26f5cdf0..aee698185432c7a3c3fe55718d7f7ba23dce315a 100644 (file)
@@ -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 */
index 85194828850a865bf39d92793f4ac722e39f39e5..d1b57084ef83f838083083a8768cce156c2f8b6c 100644 (file)
@@ -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;
 
index 81280f302f91c30a7a152606e2f02b2099f7309f..4091c92c7322dbd65d90e44478cc875dbc450daa 100644 (file)
@@ -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;
index 7284d6cea60697ffc8e15e85e2bf67846cf0fe70..41fe64606bfd217d93dabc3ebf4394d855e3bdea 100644 (file)
@@ -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)
index 8e75e5c6ac441f0ed495e8c9818fd58952eeff91..0ea0b7c18526b2acbf7802cccf357900ba2faea1 100644 (file)
 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,
index 56eac9dc32a30071f2a4d49929bfa72c752ff4fc..e0dcdb490fcf2c12f732663fa50d2a49e8dfc959 100644 (file)
@@ -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 (file)
index 0000000..b0c4c48
--- /dev/null
@@ -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 */
index ff2a59ba2dfd3e2489c9c8308e66d8487574bde1..17e692d13954d38b7a3e0229a85863dd565c7289 100644 (file)
@@ -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,
index e64b10bf24787452081c01262c3ff839b0a632ed..4642f14d35ad0af74572a954b5aec6af32676a86 100644 (file)
@@ -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)
index b9043115395f1b2484ccf4b7dde680e3e7c1aea7..c67656cfd134314ea2d859f986c8107ab7a58ead 100644 (file)
@@ -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)
 {
index 3cc010c148d454cdf4147367d4acb69a33b75b0d..44d7185567a6d549f8c68ec07c5afba5a7bda296 100644 (file)
@@ -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)
 {
index a3659258545f2886c1929316b73ea89d164b333a..9c78e1573577e562adc697f9d48c03afe2f9d93f 100644 (file)
@@ -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
index 6be5d15ec4f80aef36d935ca1567fc4b6057213d..cedee83d822b14a5df809993c15c7e5cedb8e50e 100644 (file)
@@ -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(
index 7a2b8a1c835e1bd8331e6e98d7987a32b9702a40..de11a9eab36bfb43ea6c4414857f74e734dc43d6 100644 (file)
@@ -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
+}
index 6c80841e3c2b904ec20a8b1766bae21ef11e01e9..694edf7638aad6b39500dd57af8bb6680f005968 100644 (file)
@@ -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
index 6a658444c6ddb7d53bd86128086215069cf4aa29..5cd82080f5442759d664fdbec8d4ce58f666bf31 100644 (file)
@@ -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);
 
index e0db30cd13e1681f04cc5ee708e0ec015b95561a..acfb0631cc0ef2d3722423c71dc7318072ed29c0 100644 (file)
@@ -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);
index 35733e743858a44da28a33d863d1ff15d8136810..a3c148c9c9362945067fc1ba3bb63bf0f745d7c1 100644 (file)
@@ -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;
index d6defd7149fd1aa43a09fc2850662dbae16bae4a..ea6cb9339a6d39ef6073c0c68971d1a5b14778cf 100644 (file)
@@ -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) $<
index 9eac9b410a4a76d08229b8761b6c9653da26bc4d..4078634f75fef55b3e41a07c7fae64ef792aff57 100644 (file)
@@ -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)
 {
index 92db07677ae06f5b8b71b993a4e4ea142e98373c..5fe8d82473b10a9bb18306fcde68e4d94738b4da 100644 (file)
--- a/lib/vty.c
+++ b/lib/vty.c
 #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");
index 430579c5a8776caf5b541138425d9029dd2e0750..0b3fd2443f954cf14e65e169c4e2d122a594b40f 100644 (file)
--- a/lib/vty.h
+++ b/lib/vty.h
 #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"
index 8ec82ab7bb91c5bd0f3def83b7e981e7f3f0af0e..fd6eb7db0d60a59c5c503a14354d6f051ed0eb44 100644 (file)
@@ -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);
index c3ea2a16fffa857e2c9374b96cd9659c0cd300e2..731769abf744ac595dcf5b6028f9c09761edb6a3 100644 (file)
@@ -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.
index 53ae5b4e9e2c240d961e0967e688daef4fba399f..b2f5e5a848cc9a5bbde37ecd912407930a378eee 100644 (file)
 #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>
 
index dd8dbfaffd155b6f8259a5204106119f22c10a3a..5eebda9debc4a4b50737746cdffc6a30a415857c 100644 (file)
@@ -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,
index 3a8baa2342ddd1a75e75c81e3db13737f4315dcf..53ba9eb12f3b0d449edd47291f6db72873c38d52 100644 (file)
@@ -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;
 }
 
index dc0c162c832f35c86d8485d50049ce771e6d896b..227ff6c6787ddcb1e95833347b8fa739552a3e21 100644 (file)
@@ -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
index a0cb455798030283e048a2c0afcc4104a17fd415..6a4236e7174e0769d8649052174e67996b6591e7 100644 (file)
@@ -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);
index ae3ce2f0c7c85315813f0f19a8107ee78607e949..07061b6f578fa493229504c56c3806cf6fa25ed9 100644 (file)
@@ -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__,
index d7de66c6631f6d7ea5a652c2b3b10a4b90118eba..1f7fefa048ab92f15048fb6e22f16b2a89badf3e 100644 (file)
@@ -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);
 
index f8b37d803f1b1514f4ab5ca7fc41bcae20169213..771a710240b80154bbd809b2727f4f7633997104 100644 (file)
@@ -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();
index 155374d3f0b35f224d4ef84dc6e98c6976d823bd..ed228f46ae7a52c6a5e49be180bc32ef8e797e83 100644 (file)
@@ -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)
index 779076f387f2c132794acf889bf556b38508e141..2792820a542a81419cc46e482afe2f531d9c1072 100644 (file)
@@ -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");
index b1bff69f06d15290328c97849f6f663a23dac619..f35c9df4a5a52d442641f31c63f529651ffc5436 100644 (file)
@@ -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;
index 02234cc8bd91e12b89e2e34d60e532c8d30ec7af..3cc45d900dfb38e31df1e28317313ae528fa4ef3 100644 (file)
@@ -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);
index 8e964393f100d81076014c633229c3b15e99e011..db94b85b1b5bef5193c534ae69379d9af8079a45 100644 (file)
@@ -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++;
index d48e85cedb462535e0d0685186ced10d580ad71c..eb89a14cd3829db7ea28dc947589e5d677a18a0a 100644 (file)
@@ -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;
index a16f4f73eb6ae4a25e0b6236aebb93baa57b3234..fe742b912fb0ebb6386416e72c85270010e0a713 100644 (file)
@@ -115,6 +115,8 @@ DEFUN_NOSH (show_debugging_ospf6,
 
        config_write_ospf6_debug(vty);
 
+       cmd_show_lib_debugs(vty);
+
        return CMD_SUCCESS;
 }
 
index cf863ff5234908ab01758bb803a91eae4079ee72..3dff03956ceaa421520afdb753e47414f46c4d48 100644 (file)
@@ -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
index b5e6389d4c9b0cee3690537ed72bafe56753a36e..05c5e7789d3ab3d5793fb562ab1283c3270ed2c0 100644 (file)
@@ -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;
index 6d1eb7f64f45ca3cb4ad87c51570da689ff8bce5..b904937c2ab0da2e0c521b4dc0bdae09c69dae65 100644 (file)
@@ -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);
index 3cfee7d573a98182d210603ea9c8a5b6d56cb64c..edf814184ac2b9ca581faccb8f2259549de2b865 100644 (file)
@@ -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);
 }
 
index c7cfc88b9c0fac89100094a3f4d219b3f3ba5315..8e3c68445f018c13db619ca875e8d4e7bdd0df72 100755 (executable)
@@ -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()
 
index e15f4a6bf7b7b0f76f981e02b57b74ebffe1b0df..c523638fb3cac217db4c1c15b7051dd3ce62c71d 100644 (file)
@@ -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)
index 8636db450b402fc1e8a35d9e7f5886e085cd425a..9a134d033c339ddbead85c6c6f950a14a86fce81 100644 (file)
@@ -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));
index 51c8c52ce542c57883d7336cb300af4dac6c9b78..6f569e962d93ee3c1f6e71265edfd5e9003fb62c 100644 (file)
@@ -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);
index f5ed77dab59099ae18d51a920d495c0374375535..0c2ee0c4f8a934f8303dfef7211c3c9aef672207 100644 (file)
@@ -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.
         */
index 258a93fb16fc92943488af27f0f7c7692cd4b119..a47ed8d67abdf37e74b56c20dbde00e415e9c913 100644 (file)
@@ -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);
 
index 251be7c8d177f65f0ae83735f3a4995b01772371..e9ba8fc7981160a974903c7f566115a7e832b975 100644 (file)
@@ -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)
 #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[];
index e686a93ba9f79afb2fc2dabcbf836267e7db6be0..4bbeee2d74d587aaa7e0eacc8f9ab5f93da597ee 100644 (file)
@@ -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);
 }
 
index 66ef1d6564d967e5855af6cf9986860064704dae..6678d8c1f362331597e75d99e3ab9c41ee9cc4df 100644 (file)
@@ -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);
 
index 646d3183627df87bb912f285023ee12198e7e371..a0b14e73ee995ffe92162644b96af3fca238f4ef 100644 (file)
@@ -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)
index 77e96f1733872af000af99e4100dad2981d2ee83..7b1fa6626f3ac3fc7cae81702765f7985d20bd9f 100644 (file)
@@ -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,
index 0df0072f6d7cc548b55ce1bd5cdede25fde644f0..a67b6c6c19586e352174f3686ea85513878df42b 100644 (file)
@@ -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];
index 97c15d1e3c99c00457b3c017377e4ba6c441a5a6..4e884fa89bda07e960d8b41132a846b9fee611c1 100644 (file)
@@ -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 *);
index f4fb858a5f4b2fbb0ca2e7dae7e3e9a26ccea75e..3c65ac388d323aa4176d01d39252f8ebfda6fa8b 100644 (file)
@@ -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)
index 28384438923f46de2a8de24d39e34f545bf07949..5577a291be771ce0122a80e6245742c754dfe3cf 100644 (file)
@@ -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");
index 9bd0a844af8159990834658bc3512f23cc2c725b..3d2133b11abd93a040ba8c1a6a633c4355bd4fbb 100644 (file)
@@ -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 */
index 261d69df338d5bd24a3853f6ef72a746eaa02149..ab647625fe93e0fdc38ffe23868618d22c5a57bb 100644 (file)
@@ -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:
index 9c768779086388a9c5248ce11ef83661ca783dd3..05fe6deac09a49ada2dbf8c46cac36314d9b67b4 100644 (file)
@@ -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 (file)
index 0000000..eed948b
--- /dev/null
@@ -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 (file)
index 0000000..d0a6f6e
--- /dev/null
@@ -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 */
index 57643f637edaa240c49154d34d52f4c21ba66b26..8c87a568c0bc38d23737447316325ed6803b8596 100644 (file)
@@ -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;
index 6360d8ec601d8fc033cb93464b0c8449ece4bf9e..26f593f08971bd007564365fbf73e019ba2a217b 100644 (file)
@@ -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;
 
index fa9478fcedb2bd4136c7f06d244ffca31b7e6e08..e7e2b651c56a61022e684c5fee0eea15510ab51c 100644 (file)
@@ -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 */
index 4edc1de8119e719ee6b74ff1d18333a05ef716ae..24ca4dcbf4193de46a9833fc995e88b33caaec56 100644 (file)
@@ -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);
 }
index 834bfd0bb02eccb01e14c4db603d04e719ffc4b7..2578051c2c04f901e3fde1c96cfa9644d6f2dbe8 100644 (file)
@@ -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 */
index c957c8c014e0757e89b9b396b2a9ed35590270a7..0bab045ef43b9339fd9f071abc43867534a3f5dd 100644 (file)
@@ -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);
index 1754512b5b158a831dca4cb7c325a5b67209d5e0..461586424417eb4eb60e9418c906e27b75c4757c 100644 (file)
@@ -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;
        }
index e0c36d86fea0b9d497566c9952140cd7dd4514b4..3f82d869214702ffa317f5098d84e6ac75bd2aec 100644 (file)
@@ -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);
index 3a43010f85f6faff7721114fcb2de3670a77b50a..c7735136bce63f466b6068ae06601bfecf1b32b7 100644 (file)
@@ -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. */
index 4f9cbc7b1ee691c3efa2c323065bb3ed3e674cf4..b67f942883d096f87af2e3a6081d08247a4da48f 100644 (file)
@@ -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 \
index 4775aa36fbda8a6af70f12d98c61b12596ed30f2..b88453c68f899697eaa2dd0bcedc38afe87ab7f9 100644 (file)
@@ -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);
index d2b49a7d955ee6b38cb01edb4077c94ec1dcea8c..0f259f1dc717bc5849a3bf1f8a01e9bfa0858895 100644 (file)
@@ -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
index 316255a97ee236fd63cb76423b9723dcfd13be39..5fc8a1f03252d765247edd4d10057ca8398cdb26 100644 (file)
@@ -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);
index c6897b152032e96c3de4f34eab32c95544c1fa43..5a0c8eecd337363b2b3f0f9c8cb61e261ccffc6b 100644 (file)
@@ -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 */
index e9d7cc6fc707c7a17866198819364927c7532bb2..167c88aeab1eaba4c4cbb989211ed292eee0d24a 100644 (file)
@@ -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)) {
index 81d7aa91054adfb9769ed651f4bd84bed400c1de..bb2e63c04ba725dfa44721974e059eb248dd50f4 100644 (file)
@@ -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);
index f339c792256fa54a38d9ead11733ee5b88f57f0b..29be8f463dc94a46551747a8130833d4ce75bca7 100644 (file)
@@ -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
 
index 82f045c4624ca1bd06b9eaddb7f8f6ac82a19412..99489777eb471ff94dd32990368c3f70a6ee0d5a 100644 (file)
@@ -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"};
index 59aa3676bfe6c2ffa5dbab147b5fb5acfd9d9c9a..28a7b62d10638f5186f92e44b1b3b011078fe54f 100644 (file)
@@ -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
index cbff4832a4ead2cf55b9ff1b2e2ad0b96c79c95c..298c9615198791dfc66ded835c919751db50dca7 100644 (file)
@@ -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)
 {
index ecc92cc051f4fafdc619ad4ba43c102b8f9c2529..900b7627f257d7737f914bf8b3be903b9133be5c 100644 (file)
@@ -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,
index a2b3431b94fcc346e8f8130a5bb58199cc2d9801..e8e5981ec55e09ef06fd7bc1f78e8c7d0d3f4962 100644 (file)
@@ -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;
 }
 
index bbe3f2ab71dffcf45191db0f53b44e825c4b3b7d..8a3bf31bf64cd7cc3b7606f9f6b3b8df7c92fbb6 100644 (file)
@@ -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
index 9bbfc5372b41988ac5f04f1dbabcee61825af2e9..5a244098d43081de5c253bb58cd0592f395723e7 100644 (file)
@@ -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));
 }
index e90ca1cfd8289e382d84be1e1f8aa82f197ea7d8..2d27e404072f018e7379160f9fbc01ceca6fcacc 100644 (file)
@@ -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));
index 18ccf250ae83ad643a5e164faa0e24753ff93272..47e357729ceb583076d62ba4a7f1bc8d8aa3610d 100644 (file)
@@ -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));
index b7813c5a0501e5dbc0a063faa3200d6014841955..75c2b59b66d21935eef97b0ba4dc69acc507e225 100644 (file)
@@ -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(
index 78d1072552e2b0cb20c159cfc04825506681ce28..02cf3bffbd74b44feb783fc51cfed282e01df81f 100644 (file)
@@ -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",
index e22eb6e675f7c3001ef58a3d94eef46b0a72bb58..4a97c848918604a488a5640cdcdf7ac33d9b140a 100644 (file)
@@ -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;
 
index b0f3e70b50dcd861b800f33b1ffda0a348ed2a8a..61fda163637e9721444025fab98fb81998eef0e0 100644 (file)
@@ -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;
index 696e46632a467546b6d4b02d5ff22457d99c39b8..7f90df40f24d1aa2102fbcdbd035b5606a43b3da 100644 (file)
@@ -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));
index 0286c23078a58eef02f1774b4f19edb080be01cd..c9b2588b4bd66fca973edbe769f3b441d9f534a4 100644 (file)
@@ -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_;
 }
index c564705f661924a572e63433a63cb0fd241984aa..10856cac2a6dfd2c5d60ce521601ee3d5433e4f6 100644 (file)
@@ -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(
index 627533d01ba89a6d2f0f70ba1cdcdc7d91fce4ca..22e417111ffce0f5b0ae3c8bff8a706ae1d92f5f 100644 (file)
@@ -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);
index 49248798bff8e65c6ceea2cbfea30a59447fd7ab..bd6d229476f6feee153e43d573b54e9dd24b0180 100644 (file)
@@ -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);
 }
index c45c998453511bf8e6ac74b20d115f91bc877e4e..d9ff2ca70b5a010461c0b6e7275f2e154d0a3bfb 100644 (file)
@@ -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);
 
index 23042ef14e6094a13eccab7ddf7f0f840bc5f9fd..dc5e67e2c5d9a5842ea22f242c830577bf13e3bf 100644 (file)
@@ -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 (file)
index 6ec6b11..0000000
+++ /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 (file)
index 7b87c0f..0000000
+++ /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
index c2f7396c180e75fa392616cc26ca17918d414bf3..306891c0e0ea4133ad73a7fb3495adc3b8c44de1 100644 (file)
@@ -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];
index 9283016d0814744d39dae496c6987fced134c129..b39f688cdb9d828a063c1b9f30b7f6517d2bcc51 100644 (file)
@@ -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;
+}
index 27c029670e59ce5c78bbb82f48d53170d311e7d2..d34a4af9e1ce0fec3563be79b05e0d1c7bd8e1d3 100644 (file)
@@ -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;
  */
index 6f272f008519ec911a7d95192aecf0aa8c14d0aa..db9156b04b55d2517ee0b760b430b55e8131408d 100644 (file)
@@ -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 */);
index f6c23c8e89a184bc442b530e8cd3125757c16c4c..259c34c819c8535eeb770b1c113af0e22f06289d 100644 (file)
@@ -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)
index 1d811d90016549d1af868302457a8bf84f57e5b7..1780b60a658f0219a9342821cd753c9c7020dba0 100644 (file)
@@ -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");
index 4e5fcde7dda07109129e25a8f298d8ba45d45322..385c81052eac90d6f6a94fe0edc4a57f8faf54f2 100644 (file)
@@ -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);
index 220706945daf158be81700558b635b12eddca322..f1fd2ef73506cbbb9940a6761095aebdcc853103 100644 (file)
@@ -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
index d6798c52ada579439b6b753252ce83a88b6ed272..c409b9ed0afa755990c69f85ccec4065a4853763 100644 (file)
 #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
index 12f8ffedfe28b344c4e2d27f6f2226312c7e530c..c4ff912cde99862c9c300e3cfb6aca85bd1d58b5 100644 (file)
@@ -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);
        }
 
index 9feb064e96f83d55ac0916784849db4505476843..a33da645689ed36ed0b51f530f59e28aad122be4 100644 (file)
@@ -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)
index 240e61d98ff9cdc85815835abaa82488a231f8f9..f487a21ba4c9683c28271b7eb831ff1a9fda1815 100644 (file)
@@ -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
index 4e2c44b172df88baa5b5147f698cf1598a1ae6c0..a37759e0d2fdad5e5dc4ab579b36b4eb89611054 100644 (file)
@@ -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);
index 1dce6b35626505d1dd62ceeab94a03014b08942a..c3e6a303fcb75057b3561edc3c16e1e425bf68b1 100644 (file)
@@ -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);
+               }
        }
 }
 
index a28278c5812634ca33cc06abf309bb06964270ba..d237a73126308a8724c04d693ef606f7850d41e0 100644 (file)
@@ -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)
index 8f5de3e938dc27a52e6bf94f8379bb686ac412d7..3455e30064d4b32e0d88a15867897c38a6f5412e 100644 (file)
@@ -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);
index 0742daa4de6d1a55be3d7303d30410a9ec00c517..6b58fbb5cf2c16bf777e02d1d6c0a7c5422beb59 100644 (file)
@@ -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.
                 */
index 4b67dbf1b1173327f7c5b5194202b5bcf90355d6..150e1a01ea7be5789002568d7927991d64474078 100644 (file)
@@ -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;
+}
index a4362bef90c72ad289e2e0626ba9e96420111542..6af79ddf6c77313235721f7215b0195e2fbe6ae4 100644 (file)
@@ -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 */
index 9021f1e12f560c7bc6a343eb3fd80f6f1e60ba5d..553c1314d2659e4b188843bbf961d90420921081 100644 (file)
@@ -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
 
index 87cf4341339fa0dc5e94ca87857511d7e8c01e72..0481c3a769d790170a361c9c648b8e53754e952b 100644 (file)
@@ -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)
index aa06b86479d941d13b22061d86714de4e3cfcdd0..fd7255cb87090f9c1d135e2484930be6a335c868 100644 (file)
@@ -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 \
index f80766a080844216ebca46a3041a93a472bedf59..7d9825bd10866add7b84de582bf0ef1b3e6825d2 100644 (file)
@@ -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",
index 344a1c91eec29f7c658c557276e3125f98640761..7c73598e5d5f285966c2647b6f1620d12b48040d 100644 (file)
 # 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
index 02cb2e38b313baa806049aa500a5eeb1f9f21454..d4d1f4cb8be7762878431fcbf520ec36ff500493 100644 (file)
@@ -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)
index bf994d389e1c27312baac6b44ab4c87b45198db4..0fd886221a6061885e0992e1020d1b3286f4785b 100644 (file)
 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)
index afc993b5b9982db09eeef75cc3ff41bd1173fa7c..573871fb68c746678281cd89d3e3d2927e488232 100644 (file)
@@ -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]))
 )
index bcf650b329f40709556ae3a9c4ec5c6c9a2df521..70deaa35d0e8b0bb696290583086bacb1c7b1e61 100644 (file)
@@ -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__)))
index 3ae24ea7b32c818b6711c061f826b290b43890fd..3379959dc134d60bd25d74ddb4f8e76cb1c307a2 100644 (file)
@@ -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)
index 4a6cd6ad77f10f3bfd0b0c985a9ef60ebb650bc7..b19c756738eec80b0fb304491fea1967d0ebb467 100644 (file)
@@ -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 (file)
index ef9eea4..0000000
+++ /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 (file)
index 0000000..f18aa20
--- /dev/null
@@ -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()
index 17262da8d98c60a5ff4c0821ecede551aa7448a9..c75b4cb9561092519bd3f0b6c29aae000ad6c994 100644 (file)
@@ -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()
index 5cef5d9d746e8ed2b4304a38f8e83a60c2b4e1dd..17a62f1999c8e7b468b80070f7998f6832dd62d8 100644 (file)
@@ -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
index 8f469d2a07ac3929fa84e5bc8d721036debc22ad..afe75e1f261370bfc511ad5173ff607592ab95a9 100644 (file)
@@ -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
index 73442bf16f62548c00f1634d0e652a7b2f389fe1..34ea2167264c95e4a78f09ec722b7a87f2d72c56 100644 (file)
@@ -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
index 871ee8e87ef4e0e3b3b3fc84e8f1139e501147de..ded62812a756764ab8253d877dd357d987ab9d6a 100644 (file)
@@ -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;
 }
 
index 8a321d9a91f38ed1dc8c25dc811a2bc9d32f638e..8e02f1a6c18589a7d9387770de6c0d52cfcffcb0 100644 (file)
@@ -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;
 }
 
index b00c375888fb798a2bbfb8a1c495686727c9e25a..98cc765c91cfb559d5dd6a22a663a104c653e492 100644 (file)
@@ -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
index ded2f4358e0d4ad55fc00e75816ce82d2357ee41..049a392ddbe686b0cb7ad608bc5a35c00cd6e786 100644 (file)
@@ -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
index 539c01b3ecda67121de09e6307440e780e4ab2dc..d36327cb7680f567dc01248606677019445ece58 100644 (file)
@@ -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;
 }
 
index 1e7a13d7dc61e1f2d03a8257c37f1f8c13e3e936..755debd0a4ec7a0a00e0366b9732bd56a45ff876 100644 (file)
@@ -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;
 }
 
index a4db3e5a6b6c8bf57518f64020a378b21dd2dd89..162426c58ca88debd0088f02b26d1f11204f74ff 100644 (file)
@@ -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
index a90387186e8295991494c53dece4ed01d26954b1..b032da6a1d0cb479b2abab5a69f234e843ff8242 100644 (file)
@@ -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);
 }
index 3853df7cb08a1b4d754cd29bc183c5140e794645..164a0fd218cd08fe4ac0a7bac493a085ab04e196 100644 (file)
@@ -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;
 }
 
index b40c2c6228c941298f9bd34932351f6ef294fec0..9d343576d63a1759d4b378e018047d407a284571 100644 (file)
@@ -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(
index acf4fe5d0079f269823155b5af8909f035e24bfd..3eb8d1d3b5e9ad257b4621a0114c347ccb7010d8 100644 (file)
@@ -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
index 9729be7b92e0a327a384ba59cb863625007a90ed..f634b59c75d041412dbc3e70be2f9ca56d2084ab 100644 (file)
@@ -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
index 7badd5004954f2cf6026e9b3b90eaae122d9e94a..79686158cf75775d7dfbe2e988930381cbfa4965 100644 (file)
@@ -79,6 +79,7 @@ static void sigint(void)
 
        static_vrf_terminate();
 
+       static_zebra_stop();
        frr_fini();
 
        exit(0);
index c0ace0e2588ca9d1f65c8595ea6585ba4685357a..94a3493477f1b7fda32d2f508a05389e60bf5a7e 100644 (file)
@@ -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;
 }
 
index 62969a0a2a7c766756f0e6a0c1084afb53fb713b..bb0fc95bc202b798da7b6ae5eaddd84fe8afaf48 100644 (file)
@@ -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
index bdd5b2e439a253a32ba27a993e7f49b41ed78f15..23d41b9e5dd02a1ef7f0060f033da63f2f63d654 100644 (file)
@@ -823,7 +823,7 @@ IS-IS L1 IPv4 routing table:
 \r
  Prefix         Metric  Interface  Nexthop  Label(s)       \r
  ----------------------------------------------------------\r
- 10.0.255.2/32  40      -          rt2      implicit-null  \r
+ 10.0.255.2/32  50      -          rt2      implicit-null  \r
 \r
 IS-IS paths to level-1 routers that speak IPv6\r
 Vertex               Type         Metric Next-Hop             Interface Parent\r
@@ -859,7 +859,7 @@ IS-IS L1 IPv6 routing table:
 \r
  Prefix           Metric  Interface  Nexthop  Label(s)       \r
  ------------------------------------------------------------\r
- 2001:db8::2/128  40      -          rt2      implicit-null  \r
+ 2001:db8::2/128  50      -          rt2      implicit-null  \r
 \r
 test# test isis topology 2 root rt4 lfa system-id rt6\r
 IS-IS paths to level-1 routers that speak IP\r
@@ -896,7 +896,7 @@ IS-IS L1 IPv4 routing table:
 \r
  Prefix         Metric  Interface  Nexthop  Label(s)  \r
  -----------------------------------------------------\r
- 10.0.255.6/32  20      -          rt5      16060     \r
+ 10.0.255.6/32  30      -          rt5      16060     \r
 \r
 IS-IS paths to level-1 routers that speak IPv6\r
 Vertex               Type         Metric Next-Hop             Interface Parent\r
@@ -932,7 +932,7 @@ IS-IS L1 IPv6 routing table:
 \r
  Prefix           Metric  Interface  Nexthop  Label(s)  \r
  -------------------------------------------------------\r
- 2001:db8::6/128  20      -          rt5      16061     \r
+ 2001:db8::6/128  30      -          rt5      16061     \r
 \r
 test# test isis topology 3 root rt1 lfa system-id rt2\r
 IS-IS paths to level-1 routers that speak IP\r
@@ -967,10 +967,10 @@ IS-IS L1 IPv4 routing table:
 \r
  Prefix         Metric  Interface  Nexthop  Label(s)  \r
  -----------------------------------------------------\r
- 10.0.255.2/32  20      -          rt3      16020     \r
- 10.0.255.4/32  30      -          rt3      16040     \r
- 10.0.255.5/32  40      -          rt3      16050     \r
- 10.0.255.6/32  40      -          rt3      16060     \r
+ 10.0.255.2/32  30      -          rt3      16020     \r
+ 10.0.255.4/32  40      -          rt3      16040     \r
+ 10.0.255.5/32  50      -          rt3      16050     \r
+ 10.0.255.6/32  50      -          rt3      16060     \r
 \r
 IS-IS paths to level-1 routers that speak IPv6\r
 Vertex               Type         Metric Next-Hop             Interface Parent\r
@@ -1017,7 +1017,7 @@ IS-IS L1 IPv4 routing table:
 \r
  Prefix         Metric  Interface  Nexthop  Label(s)  \r
  -----------------------------------------------------\r
- 10.0.255.3/32  20      -          rt2      16030     \r
+ 10.0.255.3/32  30      -          rt2      16030     \r
 \r
 IS-IS paths to level-1 routers that speak IPv6\r
 Vertex               Type         Metric Next-Hop             Interface Parent\r
@@ -1085,17 +1085,17 @@ IS-IS L1 IPv4 routing table:
 \r
  Prefix          Metric  Interface  Nexthop  Label(s)       \r
  -----------------------------------------------------------\r
- 10.0.255.2/32   40      -          rt2      implicit-null  \r
- 10.0.255.3/32   50      -          rt2      16030          \r
- 10.0.255.4/32   60      -          rt2      16040          \r
- 10.0.255.5/32   50      -          rt2      16050          \r
- 10.0.255.6/32   60      -          rt2      16060          \r
- 10.0.255.7/32   70      -          rt2      16070          \r
- 10.0.255.8/32   60      -          rt2      16080          \r
- 10.0.255.9/32   70      -          rt2      16090          \r
- 10.0.255.10/32  80      -          rt2      16100          \r
- 10.0.255.11/32  70      -          rt2      16110          \r
- 10.0.255.12/32  80      -          rt2      16120          \r
+ 10.0.255.2/32   50      -          rt2      implicit-null  \r
+ 10.0.255.3/32   60      -          rt2      16030          \r
+ 10.0.255.4/32   70      -          rt2      16040          \r
+ 10.0.255.5/32   60      -          rt2      16050          \r
+ 10.0.255.6/32   70      -          rt2      16060          \r
+ 10.0.255.7/32   80      -          rt2      16070          \r
+ 10.0.255.8/32   70      -          rt2      16080          \r
+ 10.0.255.9/32   80      -          rt2      16090          \r
+ 10.0.255.10/32  90      -          rt2      16100          \r
+ 10.0.255.11/32  80      -          rt2      16110          \r
+ 10.0.255.12/32  90      -          rt2      16120          \r
 \r
 IS-IS paths to level-1 routers that speak IPv6\r
 Vertex               Type         Metric Next-Hop             Interface Parent\r
@@ -1173,10 +1173,10 @@ IS-IS L1 IPv4 routing table:
 \r
  Prefix          Metric  Interface  Nexthop  Label(s)  \r
  ------------------------------------------------------\r
- 10.0.255.8/32   40      -          rt10     16080     \r
- 10.0.255.9/32   50      -          rt10     16090     \r
- 10.0.255.11/32  30      -          rt10     16110     \r
- 10.0.255.12/32  40      -          rt10     16120     \r
+ 10.0.255.8/32   50      -          rt10     16080     \r
+ 10.0.255.9/32   60      -          rt10     16090     \r
+ 10.0.255.11/32  40      -          rt10     16110     \r
+ 10.0.255.12/32  50      -          rt10     16120     \r
 \r
 IS-IS paths to level-1 routers that speak IPv6\r
 Vertex               Type         Metric Next-Hop             Interface Parent\r
@@ -1252,7 +1252,7 @@ IS-IS L1 IPv4 routing table:
 \r
  Prefix          Metric  Interface  Nexthop  Label(s)  \r
  ------------------------------------------------------\r
- 10.0.255.10/32  30      -          rt7      16100     \r
+ 10.0.255.10/32  40      -          rt7      16100     \r
 \r
 IS-IS paths to level-1 routers that speak IPv6\r
 Vertex               Type         Metric Next-Hop             Interface Parent\r
@@ -1313,14 +1313,14 @@ IS-IS L1 IPv4 routing table:
 \r
  Prefix         Metric  Interface  Nexthop  Label(s)       \r
  ----------------------------------------------------------\r
- 10.0.255.1/32  120     -          rt4      16010          \r
- 10.0.255.2/32  110     -          rt4      16020          \r
- 10.0.255.4/32  100     -          rt4      implicit-null  \r
- 10.0.255.5/32  110     -          rt4      16050          \r
- 10.0.255.6/32  130     -          rt4      16060          \r
- 10.0.255.7/32  130     -          rt4      16070          \r
- 10.0.255.8/32  130     -          rt4      16080          \r
- 10.0.255.9/32  120     -          rt4      16090          \r
+ 10.0.255.1/32  130     -          rt4      16010          \r
+ 10.0.255.2/32  120     -          rt4      16020          \r
+ 10.0.255.4/32  110     -          rt4      implicit-null  \r
+ 10.0.255.5/32  120     -          rt4      16050          \r
+ 10.0.255.6/32  140     -          rt4      16060          \r
+ 10.0.255.7/32  140     -          rt4      16070          \r
+ 10.0.255.8/32  140     -          rt4      16080          \r
+ 10.0.255.9/32  130     -          rt4      16090          \r
 \r
 IS-IS paths to level-1 routers that speak IPv6\r
 Vertex               Type         Metric Next-Hop             Interface Parent\r
@@ -1366,14 +1366,14 @@ IS-IS L1 IPv6 routing table:
 \r
  Prefix           Metric  Interface  Nexthop  Label(s)       \r
  ------------------------------------------------------------\r
- 2001:db8::1/128  120     -          rt4      16011          \r
- 2001:db8::2/128  110     -          rt4      16021          \r
- 2001:db8::4/128  100     -          rt4      implicit-null  \r
- 2001:db8::5/128  110     -          rt4      16051          \r
- 2001:db8::6/128  130     -          rt4      16061          \r
- 2001:db8::7/128  130     -          rt4      16071          \r
- 2001:db8::8/128  130     -          rt4      16081          \r
- 2001:db8::9/128  120     -          rt4      16091          \r
+ 2001:db8::1/128  130     -          rt4      16011          \r
+ 2001:db8::2/128  120     -          rt4      16021          \r
+ 2001:db8::4/128  110     -          rt4      implicit-null  \r
+ 2001:db8::5/128  120     -          rt4      16051          \r
+ 2001:db8::6/128  140     -          rt4      16061          \r
+ 2001:db8::7/128  140     -          rt4      16071          \r
+ 2001:db8::8/128  140     -          rt4      16081          \r
+ 2001:db8::9/128  130     -          rt4      16091          \r
 \r
 test# test isis topology 10 root rt8 lfa system-id rt5\r
 IS-IS paths to level-1 routers that speak IP\r
@@ -1414,15 +1414,15 @@ IS-IS L1 IPv4 routing table:
 \r
  Prefix         Metric  Interface  Nexthop  Label(s)  \r
  -----------------------------------------------------\r
- 10.0.255.1/32  80      -          rt6      16010     \r
+ 10.0.255.1/32  90      -          rt6      16010     \r
                         -          rt7      16010     \r
- 10.0.255.2/32  90      -          rt6      16020     \r
+ 10.0.255.2/32  100     -          rt6      16020     \r
                         -          rt7      16020     \r
- 10.0.255.3/32  60      -          rt6      16030     \r
+ 10.0.255.3/32  70      -          rt6      16030     \r
                         -          rt7      16030     \r
- 10.0.255.4/32  60      -          rt6      16040     \r
+ 10.0.255.4/32  70      -          rt6      16040     \r
                         -          rt7      16040     \r
- 10.0.255.5/32  100     -          rt6      16050     \r
+ 10.0.255.5/32  110     -          rt6      16050     \r
                         -          rt7      16050     \r
 \r
 IS-IS paths to level-1 routers that speak IPv6\r
@@ -1463,15 +1463,15 @@ IS-IS L1 IPv6 routing table:
 \r
  Prefix           Metric  Interface  Nexthop  Label(s)  \r
  -------------------------------------------------------\r
- 2001:db8::1/128  80      -          rt6      16011     \r
+ 2001:db8::1/128  90      -          rt6      16011     \r
                           -          rt7      16011     \r
- 2001:db8::2/128  90      -          rt6      16021     \r
+ 2001:db8::2/128  100     -          rt6      16021     \r
                           -          rt7      16021     \r
- 2001:db8::3/128  60      -          rt6      16031     \r
+ 2001:db8::3/128  70      -          rt6      16031     \r
                           -          rt7      16031     \r
- 2001:db8::4/128  60      -          rt6      16041     \r
+ 2001:db8::4/128  70      -          rt6      16041     \r
                           -          rt7      16041     \r
- 2001:db8::5/128  100     -          rt6      16051     \r
+ 2001:db8::5/128  110     -          rt6      16051     \r
                           -          rt7      16051     \r
 \r
 test# test isis topology 11 root rt3 lfa system-id rt5\r
@@ -1511,8 +1511,8 @@ IS-IS L1 IPv4 routing table:
 \r
  Prefix         Metric  Interface  Nexthop  Label(s)  \r
  -----------------------------------------------------\r
- 10.0.255.5/32  30      -          rt2      16050     \r
- 10.0.255.6/32  30      -          rt2      16060     \r
+ 10.0.255.5/32  40      -          rt2      16050     \r
+ 10.0.255.6/32  40      -          rt2      16060     \r
 \r
 IS-IS paths to level-1 routers that speak IPv6\r
 Vertex               Type         Metric Next-Hop             Interface Parent\r
@@ -1550,8 +1550,8 @@ IS-IS L1 IPv6 routing table:
 \r
  Prefix           Metric  Interface  Nexthop  Label(s)  \r
  -------------------------------------------------------\r
- 2001:db8::5/128  30      -          rt2      16051     \r
- 2001:db8::6/128  30      -          rt2      16061     \r
+ 2001:db8::5/128  40      -          rt2      16051     \r
+ 2001:db8::6/128  40      -          rt2      16061     \r
 \r
 test# test isis topology 13 root rt4 lfa system-id rt3\r
 IS-IS paths to level-1 routers that speak IP\r
@@ -1593,10 +1593,10 @@ IS-IS L1 IPv4 routing table:
 \r
  Prefix         Metric  Interface  Nexthop  Label(s)       \r
  ----------------------------------------------------------\r
- 10.0.255.3/32  110     -          rt5      16030          \r
- 10.0.255.5/32  100     -          rt5      implicit-null  \r
- 10.0.255.6/32  120     -          rt5      16060          \r
- 10.0.255.7/32  110     -          rt5      16070          \r
+ 10.0.255.3/32  120     -          rt5      16030          \r
+ 10.0.255.5/32  110     -          rt5      implicit-null  \r
+ 10.0.255.6/32  130     -          rt5      16060          \r
+ 10.0.255.7/32  120     -          rt5      16070          \r
 \r
 IS-IS paths to level-1 routers that speak IPv6\r
 Vertex               Type         Metric Next-Hop             Interface Parent\r
@@ -1699,7 +1699,7 @@ IS-IS L1 IPv4 routing table:
 \r
  Prefix         Metric  Interface  Nexthop  Label(s)  \r
  -----------------------------------------------------\r
- 10.0.255.2/32  20      -          rt3      -         \r
+ 10.0.255.2/32  30      -          rt3      -         \r
 \r
 IS-IS paths to level-1 routers that speak IPv6\r
 Vertex               Type         Metric Next-Hop             Interface Parent\r
@@ -1731,7 +1731,7 @@ IS-IS L1 IPv6 routing table:
 \r
  Prefix           Metric  Interface  Nexthop  Label(s)  \r
  -------------------------------------------------------\r
- 2001:db8::2/128  20      -          rt3      -         \r
+ 2001:db8::2/128  30      -          rt3      -         \r
 \r
 test# test isis topology 14 root rt5 lfa system-id rt4\r
 IS-IS paths to level-1 routers that speak IP\r
@@ -1765,10 +1765,10 @@ IS-IS L1 IPv4 routing table:
 \r
  Prefix         Metric  Interface  Nexthop  Label(s)  \r
  -----------------------------------------------------\r
- 10.0.255.1/32  60      -          rt3      -         \r
- 10.0.255.2/32  60      -          rt3      -         \r
- 10.0.255.3/32  50      -          rt3      -         \r
- 10.0.255.4/32  60      -          rt3      -         \r
+ 10.0.255.1/32  70      -          rt3      -         \r
+ 10.0.255.2/32  70      -          rt3      -         \r
+ 10.0.255.3/32  60      -          rt3      -         \r
+ 10.0.255.4/32  70      -          rt3      -         \r
 \r
 IS-IS paths to level-1 routers that speak IPv6\r
 Vertex               Type         Metric Next-Hop             Interface Parent\r
@@ -1801,10 +1801,10 @@ IS-IS L1 IPv6 routing table:
 \r
  Prefix           Metric  Interface  Nexthop  Label(s)  \r
  -------------------------------------------------------\r
- 2001:db8::1/128  60      -          rt3      -         \r
- 2001:db8::2/128  60      -          rt3      -         \r
- 2001:db8::3/128  50      -          rt3      -         \r
- 2001:db8::4/128  60      -          rt3      -         \r
+ 2001:db8::1/128  70      -          rt3      -         \r
+ 2001:db8::2/128  70      -          rt3      -         \r
+ 2001:db8::3/128  60      -          rt3      -         \r
+ 2001:db8::4/128  70      -          rt3      -         \r
 \r
 test# \r
 test# test isis topology 1 root rt1 remote-lfa system-id rt2\r
@@ -2174,11 +2174,11 @@ IS-IS L1 IPv4 routing table:
 \r
  Prefix         Metric  Interface  Nexthop  Label(s)  \r
  -----------------------------------------------------\r
- 10.0.255.1/32  40      -          rt3      16010     \r
+ 10.0.255.1/32  50      -          rt3      16010     \r
                         -          rt6      16010     \r
- 10.0.255.2/32  30      -          rt3      16020     \r
+ 10.0.255.2/32  40      -          rt3      16020     \r
                         -          rt6      16020     \r
- 10.0.255.4/32  20      -          rt3      16040     \r
+ 10.0.255.4/32  30      -          rt3      16040     \r
                         -          rt6      16040     \r
 \r
 test# test isis topology 3 root rt5 remote-lfa system-id rt3 ipv4-only\r
@@ -2535,13 +2535,13 @@ IS-IS L1 IPv4 routing table:
 \r
  Prefix         Metric  Interface  Nexthop  Label(s)     \r
  --------------------------------------------------------\r
- 10.0.255.1/32  50      -          rt10     16010        \r
+ 10.0.255.1/32  60      -          rt10     16010        \r
  10.0.255.2/32  60      -          rt12     50900/16020  \r
  10.0.255.3/32  70      -          rt12     50900/16030  \r
- 10.0.255.4/32  40      -          rt10     16040        \r
+ 10.0.255.4/32  50      -          rt10     16040        \r
  10.0.255.5/32  50      -          rt12     50900/16050  \r
  10.0.255.6/32  60      -          rt12     50900/16060  \r
- 10.0.255.7/32  30      -          rt10     16070        \r
+ 10.0.255.7/32  40      -          rt10     16070        \r
  10.0.255.8/32  40      -          rt12     50900/16080  \r
 \r
 test# test isis topology 7 root rt6 remote-lfa system-id rt5 ipv4-only\r
@@ -2671,13 +2671,13 @@ IS-IS L1 IPv4 routing table:
 \r
  Prefix          Metric  Interface  Nexthop  Label(s)  \r
  ------------------------------------------------------\r
- 10.0.255.1/32   70      -          rt9      16010     \r
- 10.0.255.4/32   60      -          rt9      16040     \r
- 10.0.255.5/32   50      -          rt9      16050     \r
- 10.0.255.7/32   50      -          rt9      16070     \r
- 10.0.255.8/32   40      -          rt9      16080     \r
- 10.0.255.10/32  60      -          rt9      16100     \r
- 10.0.255.11/32  50      -          rt9      16110     \r
+ 10.0.255.1/32   80      -          rt9      16010     \r
+ 10.0.255.4/32   70      -          rt9      16040     \r
+ 10.0.255.5/32   60      -          rt9      16050     \r
+ 10.0.255.7/32   60      -          rt9      16070     \r
+ 10.0.255.8/32   50      -          rt9      16080     \r
+ 10.0.255.10/32  70      -          rt9      16100     \r
+ 10.0.255.11/32  60      -          rt9      16110     \r
 \r
 test# test isis topology 8 root rt2 remote-lfa system-id rt5 ipv4-only\r
 P-space (self):\r
@@ -2863,14 +2863,14 @@ IS-IS L1 IPv4 routing table:
 \r
  Prefix         Metric  Interface  Nexthop  Label(s)       \r
  ----------------------------------------------------------\r
- 10.0.255.1/32  50      -          rt1      implicit-null  \r
+ 10.0.255.1/32  60      -          rt1      implicit-null  \r
                         -          rt3      16010          \r
- 10.0.255.3/32  50      -          rt1      16030          \r
+ 10.0.255.3/32  60      -          rt1      16030          \r
                         -          rt3      implicit-null  \r
  10.0.255.4/32  80      -          rt3      50500/16040    \r
- 10.0.255.5/32  60      -          rt1      16050          \r
+ 10.0.255.5/32  70      -          rt1      16050          \r
                         -          rt3      16050          \r
- 10.0.255.6/32  70      -          rt3      16060          \r
+ 10.0.255.6/32  80      -          rt3      16060          \r
 \r
 P-space (self):\r
 \r
@@ -2941,14 +2941,14 @@ IS-IS L1 IPv6 routing table:
 \r
  Prefix           Metric  Interface  Nexthop  Label(s)       \r
  ------------------------------------------------------------\r
- 2001:db8::1/128  50      -          rt1      implicit-null  \r
+ 2001:db8::1/128  60      -          rt1      implicit-null  \r
                           -          rt3      16011          \r
- 2001:db8::3/128  50      -          rt1      16031          \r
+ 2001:db8::3/128  60      -          rt1      16031          \r
                           -          rt3      implicit-null  \r
  2001:db8::4/128  80      -          rt3      50500/16041    \r
- 2001:db8::5/128  60      -          rt1      16051          \r
+ 2001:db8::5/128  70      -          rt1      16051          \r
                           -          rt3      16051          \r
- 2001:db8::6/128  70      -          rt3      16061          \r
+ 2001:db8::6/128  80      -          rt3      16061          \r
 \r
 test# test isis topology 13 root rt1 remote-lfa system-id rt3 ipv4-only\r
 P-space (self):\r
index 2e45186653ba829e073cb93862ac22272db2c0e9..33c26501ba357c04002e845524b7005c258f4d11 100644 (file)
@@ -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
index 188f810f819abdb66b856e76ccef0751f983094f..61af44a4ddddb52d29a8b0227964e68145067282 100644 (file)
@@ -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
index b38701a53d94a2029b4e066795249940f87cf35b..b2e8de5ce13bfbca957ee0d93c861e9c76a3ab0c 100644 (file)
@@ -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
index 82b64c0d98d8fa51c26502d8e136927a927025ed..7bee704182edff3caf208f0b93499a0ffa15ee00 100644 (file)
@@ -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
index fd333b3084cc96a102c00e1504c20505b5f2aa90..31071e760d467d24d826ab82d1a029426e893b41 100644 (file)
@@ -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
index 3be6cd3d7b1ba656e3d02567b7639ac0db2e0097..53c4793bf4ce099134c5efafab7777fe883dc89e 100644 (file)
@@ -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
index 20034b7408826a4632868e0dbdf93a681f2c6573..fe3f0720d81449a617532dc5330449c73d2f550b 100644 (file)
@@ -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
index fffee63c6b5e6be5c65c137427483a395fbe3c5d..363b4f5349e233c268dc7be6e48904aa05efcb3d 100644 (file)
@@ -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
index 5b5f8596cfa1f39a01a0b934f1830068232248e1..8c3229b45d00dde0cadef4ab51912bede3077786 100644 (file)
@@ -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
index ff856792568af02dbd2fc9cbe30e9f4a4319a9ec..cb63da47153c352cf86f8a0c8d06e7eef784c273 100644 (file)
@@ -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
index ca8c005f9ec705d6bca7c602082abc3cb57c0f1b..2d3e2a7594f12f47ee93353f3c5568d2d6180b0d 100644 (file)
@@ -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 (file)
index 0000000..e69de29
diff --git a/tests/topotests/bgp_accept_own/ce1/bgpd.conf b/tests/topotests/bgp_accept_own/ce1/bgpd.conf
new file mode 100644 (file)
index 0000000..fa53a42
--- /dev/null
@@ -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 (file)
index 0000000..7863ae1
--- /dev/null
@@ -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 (file)
index 0000000..cdf8898
--- /dev/null
@@ -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 (file)
index 0000000..829967e
--- /dev/null
@@ -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 (file)
index 0000000..8631293
--- /dev/null
@@ -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 (file)
index 0000000..7c1ea33
--- /dev/null
@@ -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 (file)
index 0000000..1a5e1a0
--- /dev/null
@@ -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 (file)
index 0000000..71476d2
--- /dev/null
@@ -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 (file)
index 0000000..4f0a6ab
--- /dev/null
@@ -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 (file)
index 0000000..0369901
--- /dev/null
@@ -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 (file)
index 0000000..b598246
--- /dev/null
@@ -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 (file)
index 0000000..aa3f633
--- /dev/null
@@ -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 (file)
index 0000000..161530b
--- /dev/null
@@ -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 (file)
index 0000000..e69de29
diff --git a/tests/topotests/bgp_aigp/r1/bgpd.conf b/tests/topotests/bgp_aigp/r1/bgpd.conf
new file mode 100644 (file)
index 0000000..74a0215
--- /dev/null
@@ -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 (file)
index 0000000..38aa11d
--- /dev/null
@@ -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 (file)
index 0000000..0ed22d3
--- /dev/null
@@ -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 (file)
index 0000000..ae72f21
--- /dev/null
@@ -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 (file)
index 0000000..ed31941
--- /dev/null
@@ -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 (file)
index 0000000..6d6a557
--- /dev/null
@@ -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 (file)
index 0000000..7572e26
--- /dev/null
@@ -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 (file)
index 0000000..f971ad6
--- /dev/null
@@ -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 (file)
index 0000000..82c87d5
--- /dev/null
@@ -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 (file)
index 0000000..d2b96b7
--- /dev/null
@@ -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 (file)
index 0000000..c9e6796
--- /dev/null
@@ -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 (file)
index 0000000..5f544e8
--- /dev/null
@@ -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 (file)
index 0000000..9448722
--- /dev/null
@@ -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 (file)
index 0000000..b853c74
--- /dev/null
@@ -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 (file)
index 0000000..69b8bf2
--- /dev/null
@@ -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 (file)
index 0000000..15d9437
--- /dev/null
@@ -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 (file)
index 0000000..46b2933
--- /dev/null
@@ -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 (file)
index 0000000..f8ca5f8
--- /dev/null
@@ -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 (file)
index 0000000..00d85cf
--- /dev/null
@@ -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 (file)
index 0000000..4c05df8
--- /dev/null
@@ -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 (file)
index 0000000..9fa80c6
--- /dev/null
@@ -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))
index b18e32f6bd4beae6fcf0fe52427008e6f7d1162f..42b9b8adb9ed673fc1c7d6a65562e187b8dd0480 100644 (file)
@@ -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)
index e4c25ff5cb1a60e366aa908c70f231ca1eab9e9e..1c1a5cdfe49234a0344ba2f3133e241551f9690b 100644 (file)
@@ -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")
index f6ee9ea79597c2667cc5649b494d65ce8c504abf..a93061740f87eaaad877fb998347424a59aed2fe 100644 (file)
@@ -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 (file)
index 0000000..e69de29
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 (file)
index 0000000..1e98f4e
--- /dev/null
@@ -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 (file)
index 0000000..acf120b
--- /dev/null
@@ -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 (file)
index 0000000..66c3dc5
--- /dev/null
@@ -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 (file)
index 0000000..6c013e2
--- /dev/null
@@ -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 (file)
index 0000000..f229954
--- /dev/null
@@ -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 (file)
index 0000000..5058d40
--- /dev/null
@@ -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 (file)
index 0000000..268163e
--- /dev/null
@@ -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 (file)
index 0000000..591bac1
--- /dev/null
@@ -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))
index 2784e956fa389d1a2a818fc2f99d5e84c3b4095b..8fd0120dd82172a9061d3625bcdd5a2d625e6127 100644 (file)
@@ -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:
index 704e8fdf04a63c46ffef1b7f3df3f225a6fcf215..185a086838683cd04f3d0839e3ae14a38c8d192c 100644 (file)
@@ -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:
index 2a51dc83ef429045de2b9ae5ec9f4644e7041292..9b6480c0d3f884d3a14e1bfbb32349fb75b01950 100644 (file)
@@ -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)
index f155325502b31ef78299fdaa022232f8cf7afbf2..deca4bcfd7d690d4f1e7abab45fd1bcc800c3a1a 100644 (file)
@@ -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)
index dda3bd4b30758ef3b0ff54d892213e5fec4eb72c..a92fde2d0dca81d4a226bec428f90b2efc3bd728 100644 (file)
@@ -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))
index e4b533b295afc84548c3aa894ff27681bc026329..b0166033df6a39df643003f11cc579ecfccca951 100644 (file)
@@ -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")
index 835ef41de1696585ecf6e10dd98f64890967e3e5..f408ff4854833cf2deab45c8b0f0049702aa622f 100644 (file)
@@ -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")
index 3afe38857ba0bd1a5ef1b4478171b02f26debd7b..293f3042eb692abe82239c6bfd0ce5cec3341aa9 100644 (file)
@@ -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)
 
index 535f272ef4096cc4ce15c9f6d16efe893cb13885..fe885372d5af66422529a399b47577622569c5c9 100644 (file)
@@ -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)
 
index e60552ed101cfe500bc523da5928d05f920b97b0..4ff62a97858ea63c044805800c701c93e1ff3644 100644 (file)
@@ -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)
index 1df77ebeb2089602f0e493ab11dd4072cbbf6a08..fd1ef097c4420389d0bab7b96d4f6ed3c1f00b0f 100644 (file)
@@ -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"])
index 6bf8b963098324514a4125a88286bacbe4a9996a..76522206a419d5bf761821452548bbbffb962d0e 100644 (file)
@@ -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)
-
index c03dd7e197af29dc1d4ee6a1c8a837e097140340..758d797ad693735cfaa1ecd7913125fca0f2b1c0 100644 (file)
@@ -1,3 +1,4 @@
+no zebra nexthop kernel enable
 !
 interface r2-eth0
  ip address 192.168.255.2/24
index 58133c44a97068fb39a55cf7dff5c9042b173c94..684d2fcb57925551fa1c03b1dfb39a071da31ed9 100644 (file)
@@ -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))
index a79ce0e3a0e91ea9325d380a786fd7229a7406d1..16572a7967e6cecee302800a093f6ea209cb2fd1 100644 (file)
@@ -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 (file)
index 0000000..a842c9e
--- /dev/null
@@ -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 (file)
index 0000000..7184679
--- /dev/null
@@ -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 (file)
index 0000000..da665be
--- /dev/null
@@ -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 (file)
index 0000000..51f9bb2
--- /dev/null
@@ -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 (file)
index 0000000..d415b63
--- /dev/null
@@ -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 (file)
index 0000000..311ccce
--- /dev/null
@@ -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 (file)
index 0000000..8f7e128
--- /dev/null
@@ -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 (file)
index 0000000..d7c480d
--- /dev/null
@@ -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 (file)
index 0000000..925980a
--- /dev/null
@@ -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 (file)
index 0000000..6f4dc1b
--- /dev/null
@@ -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 (file)
index 0000000..5e2503f
--- /dev/null
@@ -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 (file)
index 0000000..5992e06
--- /dev/null
@@ -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 (file)
index 0000000..e69de29
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 (file)
index 0000000..41bf963
--- /dev/null
@@ -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 (file)
index 0000000..7c2ed09
--- /dev/null
@@ -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 (file)
index 0000000..187713d
--- /dev/null
@@ -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 (file)
index 0000000..fd45c48
--- /dev/null
@@ -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 (file)
index 0000000..a83d433
--- /dev/null
@@ -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))
index 2dc95cee21a82dfe06da20c2dedb800c3087dd4f..5131a89ce832512903b57e124b0842887fc78f71 100644 (file)
@@ -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)
 
index 655a3dc8991e84a36562c2cb55d47164e71a140a..77bddbe3372491e5abcc8df38a52397b37dde672 100644 (file)
@@ -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(
index 4da7eeb2ff2b87de314fdd8c167154788198a673..589482d6a594ca17650598dc2466c04d6297715d 100644 (file)
@@ -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)
 
index 8defa0125a74498e2d716f531b013bb9658ea1b4..8ccf7a2a34066414cbd56fda3e78823bdc9a0c13 100644 (file)
@@ -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
   !
  !
 !
index 51d9c9223588c1b8b4a808f2e2594e71838b6a62..839454d8a8b343531a24125d6c9db4d34e9ecde9 100644 (file)
@@ -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
   !
  !
 !
index a43cec20ef0d0a3c9a30bcecf6274e18ce1e840a..a9319a6aeddbd454f50093d2f58b3f25d8a9fbcc 100644 (file)
@@ -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
   !
  !
 !
index 71ddedf6ff75088677081a1b04a4d5e6283f53b5..9e5fa0ac073f6cd344754e296793c1b065e2d7cc 100644 (file)
@@ -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 (file)
index 0000000..3459796
--- /dev/null
@@ -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 (file)
index 0000000..1d33fee
--- /dev/null
@@ -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 (file)
index 0000000..d19e315
--- /dev/null
@@ -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 (file)
index 0000000..58e851d
--- /dev/null
@@ -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 (file)
index 0000000..8ed9978
--- /dev/null
@@ -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 (file)
index 0000000..a21f4a1
--- /dev/null
@@ -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 (file)
index 0000000..35ff14e
--- /dev/null
@@ -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 (file)
index 0000000..0612c53
--- /dev/null
@@ -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 (file)
index 0000000..a85d970
--- /dev/null
@@ -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 (file)
index 0000000..38a7807
--- /dev/null
@@ -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 (file)
index 0000000..2f2931f
--- /dev/null
@@ -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 (file)
index 0000000..d08fdad
--- /dev/null
@@ -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 (file)
index 0000000..93fb32f
--- /dev/null
@@ -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 (file)
index 0000000..a0be78e
--- /dev/null
@@ -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 (file)
index 0000000..8a98768
--- /dev/null
@@ -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 (file)
index 0000000..897ed46
--- /dev/null
@@ -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 (file)
index 0000000..2ab6f2d
--- /dev/null
@@ -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 (file)
index 0000000..dc338d5
--- /dev/null
@@ -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 (file)
index 0000000..80ff52a
--- /dev/null
@@ -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 (file)
index 0000000..a290213
--- /dev/null
@@ -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 (file)
index 0000000..e0b6540
--- /dev/null
@@ -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 (file)
index 0000000..4a603a5
--- /dev/null
@@ -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 (file)
index 0000000..ace6136
--- /dev/null
@@ -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 (file)
index 0000000..5a83e90
--- /dev/null
@@ -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 (file)
index 0000000..01b0cc3
--- /dev/null
@@ -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 (file)
index 0000000..3cc2fdd
--- /dev/null
@@ -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 (file)
index 0000000..5645540
--- /dev/null
@@ -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 (file)
index 0000000..7a4e0d7
--- /dev/null
@@ -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 (file)
index 0000000..eb34333
--- /dev/null
@@ -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 (file)
index 0000000..5517fc7
--- /dev/null
@@ -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 (file)
index 0000000..25b7a86
--- /dev/null
@@ -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 (file)
index 0000000..f2df9be
--- /dev/null
@@ -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 (file)
index 0000000..0fdd3d6
--- /dev/null
@@ -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 (file)
index 0000000..a1f2158
--- /dev/null
@@ -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 (file)
index 0000000..7eeccd1
--- /dev/null
@@ -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 (file)
index 0000000..cc96f43
--- /dev/null
@@ -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 (file)
index 0000000..0c9ae73
--- /dev/null
@@ -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 (file)
index 0000000..cf0fd18
--- /dev/null
@@ -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 (file)
index 0000000..e486e74
--- /dev/null
@@ -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 (file)
index 0000000..2c560df
--- /dev/null
@@ -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 (file)
index 0000000..8700f12
--- /dev/null
@@ -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 (file)
index 0000000..9557054
--- /dev/null
@@ -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 (file)
index 0000000..e3edee1
--- /dev/null
@@ -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 (file)
index 0000000..0dcdec6
--- /dev/null
@@ -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 (file)
index 0000000..d801671
--- /dev/null
@@ -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 (file)
index 0000000..25da05b
--- /dev/null
@@ -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 (file)
index 0000000..2cd47b9
--- /dev/null
@@ -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 (file)
index 0000000..25cdf03
--- /dev/null
@@ -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 (file)
index 0000000..03bbcc0
--- /dev/null
@@ -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 (file)
index 0000000..f390ef6
--- /dev/null
@@ -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 (file)
index 0000000..3353d75
--- /dev/null
@@ -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 (file)
index 0000000..1534e98
--- /dev/null
@@ -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 (file)
index 0000000..a2e329d
--- /dev/null
@@ -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 (file)
index 0000000..49d1861
--- /dev/null
@@ -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 (file)
index 0000000..f7433d5
--- /dev/null
@@ -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 (file)
index 0000000..b9277a9
--- /dev/null
@@ -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 (file)
index 0000000..e410bbb
--- /dev/null
@@ -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))
index bc4d0f4796bc6539bea02807b16d4ae4fa82e255..1a5ede276d8e3e111dbcd2c7480520386b95593b 100644 (file)
@@ -32,7 +32,7 @@
       ],
       "peer":{
         "peerId":"10.0.0.2",
-        "routerId":"10.0.0.9",
+        "routerId":"60.0.0.1",
         "type":"external"
       }
     }
index 16561ce837f97c65014a3a87e8be145423e36c61..4a35abfd6fd57a83069e41198d930f748ed0e929 100644 (file)
@@ -61,7 +61,7 @@
       ],
       "peer":{
         "peerId":"0.0.0.0",
-        "routerId":"10.0.0.9"
+        "routerId":"60.0.0.1"
       }
     }
   ]
index ebef2012a800c76b2cfee3b984a6b231d9c6de32..010e86aad704a10ef0f86da60b1eaa857282d249 100644 (file)
@@ -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
index 443fffc7032923433b369745bee58c722c7bd09a..6e8bce0450ddaffc16fe07cf941f4e8fb3911180 100644 (file)
@@ -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 (file)
index 0000000..ab8c3aa
--- /dev/null
@@ -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
+        }
+      ]
+    }
+  ]
+}
index 2c87d9d7b0f80b543e5e7372c531336f5d967396..96a294cae3453bc797c62d5678c5cbe3f62fefc8 100644 (file)
@@ -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"
index 3aa0cad439a274e34cbea0788faf45f0546a8c95..3b615b0cb4b4545daac60df0b3397454e5d95aa1 100644 (file)
@@ -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
index 1cc37ba124ca47279621a0b8738fc4208920c29f..55d9563b61206320798f4f64fb439e5902a20dcf 100644 (file)
@@ -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
index d3d1f9e406783be1ed4664fea10b286c260edc92..da240e87a35b7297752afc96e1391c33e54f346f 100644 (file)
           "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
           "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
           "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
           "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
           "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
           "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
           "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,
           "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
           "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
           "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
           "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
           "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
           "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,
           "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
index 1b71ac3a17e3c7266437b187cf100325b7496fd3..220ec49768b834c63ee05d9639e3f88560ce47b4 100644 (file)
@@ -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 (file)
index 0000000..86cf68d
--- /dev/null
@@ -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 (file)
index 0000000..e69de29
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 (file)
index 0000000..a00d2d3
--- /dev/null
@@ -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 (file)
index 0000000..5e48511
--- /dev/null
@@ -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 (file)
index 0000000..40357a4
--- /dev/null
@@ -0,0 +1,6 @@
+hostname rt2
+!
+bfd
+ peer 2001:db8:1000::1 multihop local-address 2001:db8:1000::2
+ !
+!
index 7e902213e711ecd46ede779f709b11af8f992a44..f72942b60761dbb083eda9fb3e5bcf6983353741 100755 (executable)
@@ -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."
index 814d8f8c978c49d5e6dbc79595976ab901c14819..2e96d5c53d323151b645c65b114f8e46926e8aa5 100644 (file)
@@ -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
index 26b48ded7856b8b5ce495ba8b345b8a5b9d0c79a..a25b78579f412cafb61868b817fb8a6198d2a2bb 100644 (file)
@@ -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
index 027dd806cff32c798f1ee7d075c105f16dbe403c..d7711b7e59116b11cf95f9f0a51b6053ecf2ec2b 100644 (file)
         "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
             }
           ]
         }
         "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
             }
           ]
         }
         "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
             }
           ]
         }
           "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
             }
           ]
         }
         "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
             }
           ]
         },
           "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
           "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,
         "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
             }
           ]
         }
         "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
             }
           ]
         }
         "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
             }
           ]
         }
         "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
             }
           ]
         }
           "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
             }
           ]
         }
           "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,
         "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
             }
           ]
         },
index 2e9a5ec84c2144b5a759983cb1db74e571a1925e..7b2074b69c772d3eb199a89f7ba39d94a024687d 100644 (file)
         "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
             }
           ]
         }
           "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
             }
           ]
         }
         "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
             }
           ]
         },
           "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
           "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,
         "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
             }
           ]
         }
         "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
             }
           ]
         }
           "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
             }
           ]
         }
           "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,
         "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
             }
           ]
         },
index 5c7ccdd6a2bd032a69a07fda6a2a139d7b528f85..528138477a53389cf23a378ff3c1035f30657b10 100644 (file)
           "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,
         "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
             }
           ]
         }
         "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
             }
           ]
         }
           "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
             }
           ]
         }
         "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
             }
           ]
         },
           "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
           "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,
         "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
             }
           ]
         }
         "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
             }
           ]
         }
           "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
             }
           ]
         }
           "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,
         "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
             }
           ]
         },
index 5c7ccdd6a2bd032a69a07fda6a2a139d7b528f85..528138477a53389cf23a378ff3c1035f30657b10 100644 (file)
           "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,
         "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
             }
           ]
         }
         "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
             }
           ]
         }
           "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
             }
           ]
         }
         "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
             }
           ]
         },
           "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
           "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,
         "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
             }
           ]
         }
         "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
             }
           ]
         }
           "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
             }
           ]
         }
           "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,
         "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
             }
           ]
         },
index 48d475c720f1897069d60a3a65af35f600277e99..72e441d186125c217567843ade30948c802dca1a 100644 (file)
           "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,
         "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
             }
           ]
         }
         "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
             }
           ]
         }
         "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
             }
           ]
         }
         "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
             }
           ]
         }
           "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
             }
           ]
         }
         "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
             }
           ]
         },
           "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
           "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,
         "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
             }
           ]
         }
         "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
             }
           ]
         }
         "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
             }
           ]
         }
         "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
             }
           ]
         }
           "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
             }
           ]
         }
           "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,
         "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
             }
           ]
         },
index 75443a42e8436cea449477515d024c46f46b2af2..a5f50c3ebab9753a8c963356ba73e66caad73d1a 100644 (file)
           "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,
         "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
             }
           ]
         }
         "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
             }
           ]
         }
         "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
             }
           ]
         }
         "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
             }
           ]
         }
           "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
             }
           ]
         }
         "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
             }
           ]
         },
           "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
           "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,
         "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
             }
           ]
         }
         "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
             }
           ]
         }
         "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
             }
           ]
         }
         "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
             }
           ]
         }
           "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
             }
           ]
         }
           "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
         "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 (file)
index 0000000..e69de29
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 (file)
index 0000000..e69de29
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 (file)
index 0000000..e69de29
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 (file)
index 0000000..e69de29
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 (file)
index 0000000..e69de29
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 (file)
index 0000000..e69de29
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 (file)
index 0000000..a8d6e6c
--- /dev/null
@@ -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 (file)
index 0000000..637c59f
--- /dev/null
@@ -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 (file)
index 0000000..e110bf4
--- /dev/null
@@ -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 (file)
index 0000000..e69de29
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 (file)
index 0000000..e69de29
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 (file)
index 0000000..e69de29
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 (file)
index 0000000..e69de29
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 (file)
index 0000000..e69de29
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 (file)
index 0000000..e69de29
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 (file)
index 0000000..e69de29
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 (file)
index 0000000..e69de29
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 (file)
index 0000000..84a3644
--- /dev/null
@@ -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 (file)
index 0000000..e69de29
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 (file)
index 0000000..e69de29
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 (file)
index 0000000..e69de29
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 (file)
index 0000000..e69de29
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 (file)
index 0000000..e69de29
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 (file)
index 0000000..e69de29
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 (file)
index 0000000..8695cf8
--- /dev/null
@@ -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 (file)
index 0000000..661d0fe
--- /dev/null
@@ -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 (file)
index 0000000..30941b3
--- /dev/null
@@ -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 (file)
index 0000000..e69de29
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 (file)
index 0000000..e69de29
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 (file)
index 0000000..e69de29
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 (file)
index 0000000..e69de29
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 (file)
index 0000000..e69de29
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 (file)
index 0000000..e69de29
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 (file)
index 0000000..2645c59
--- /dev/null
@@ -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 (file)
index 0000000..37e3185
--- /dev/null
@@ -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 (file)
index 0000000..186291a
--- /dev/null
@@ -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 (file)
index 0000000..d27625f
--- /dev/null
@@ -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 (file)
index 0000000..e69de29
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 (file)
index 0000000..e69de29
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 (file)
index 0000000..e69de29
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 (file)
index 0000000..e69de29
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 (file)
index 0000000..e69de29
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 (file)
index 0000000..e69de29
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 (file)
index 0000000..3d21c04
--- /dev/null
@@ -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 (file)
index 0000000..66a9dac
--- /dev/null
@@ -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 (file)
index 0000000..cdfc407
--- /dev/null
@@ -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 (file)
index 0000000..0c8ba72
--- /dev/null
@@ -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 (file)
index 0000000..e69de29
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 (file)
index 0000000..e69de29
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 (file)
index 0000000..e69de29
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 (file)
index 0000000..e477e87
--- /dev/null
@@ -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 (file)
index 0000000..12e0b59
--- /dev/null
@@ -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 (file)
index 0000000..387dcca
--- /dev/null
@@ -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 (file)
index 0000000..1086b6e
--- /dev/null
@@ -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 (file)
index 0000000..571c66f
--- /dev/null
@@ -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 (file)
index 0000000..18322f1
--- /dev/null
@@ -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
index 07e91f1a48684e8ab1ae19094fade5e5ef4ecebe..5a5b9c59dec347b851f3e31ad6f6067c4bc4c22f 100755 (executable)
@@ -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."
index 014722387f70cf1c2a77e972d708fb24ce3c75fe..8b6c3772b8d9406a11831f5d892a191938027997 100644 (file)
@@ -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():
index 7ab36c4fcdd39a6de5e3852603467c5c26b265a6..a09b0b8b2e53ea783288f9478786f69edc184f59 100644 (file)
@@ -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 = (
index 5f4c2807151ecc4a817473b29d4d5ee11096aae4..737226c7fe576a94818b95903109255d0950fd5c 100644 (file)
@@ -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
 #############################################
index 03ab02460f50cdabfb069b7667bb6037180507f6..7a57af7dbf0211a46c58a418915bc2ecae3b8908 100644 (file)
@@ -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,19 +2189,18 @@ def clear_pim_interface_traffic(tgen, topo):
     return True
 
 
-def clear_pim_interfaces(tgen, dut):
+def clear_pim6_interface_traffic(tgen, topo):
     """
-    Clear ip/ipv6 pim interface by running
-    "clear ip/ipv6 pim interfaces" cli
+    Clear ipv6 pim interface traffic by running
+    "clear ipv6 pim interface traffic" cli
 
     Parameters
     ----------
     * `tgen`: topogen object
-    * `dut`: Device Under Test
     Usage
     -----
 
-    result = clear_pim_interfaces(tgen, dut)
+    result = clear_pim6_interface_traffic(tgen, topo)
 
     Returns
     -------
@@ -1935,39 +2209,108 @@ def clear_pim_interfaces(tgen, dut):
 
     logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
 
-    nh_before_clear = {}
-    nh_after_clear = {}
+    for dut in tgen.routers():
+        if "pim" not in topo["routers"][dut]:
+            continue
 
-    rnode = tgen.routers()[dut]
+        rnode = tgen.routers()[dut]
 
-    logger.info("[DUT: %s]: Verify pim neighbor before pim" " neighbor clear", dut)
-    # To add uptime initially
-    sleep(10)
-    run_json_before = run_frr_cmd(rnode, "show ip pim neighbor json", isjson=True)
+        logger.info("[DUT: %s]: Clearing pim6 interface traffic", dut)
+        result = run_frr_cmd(rnode, "clear ipv6 pim interface traffic")
 
-    for key, value in run_json_before.items():
-        if bool(value):
-            for _key, _value in value.items():
-                nh_before_clear[key] = _value["upTime"]
+    logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name))
 
-    # Clearing PIM neighbors
-    logger.info("[DUT: %s]: Clearing pim interfaces", dut)
-    run_frr_cmd(rnode, "clear ip pim interfaces")
+    return True
 
-    logger.info("[DUT: %s]: Verify pim neighbor after pim" " neighbor clear", dut)
 
-    found = False
+def clear_pim6_interfaces(tgen, topo):
+    """
+    Clear ipv6 pim interface by running
+    "clear ipv6 pim interface" cli
 
-    # 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)
-        run_json_after = run_frr_cmd(rnode, "show ip pim neighbor json", isjson=True)
-        found = True
-        for pim_intf in nh_before_clear.keys():
-            if pim_intf not in run_json_after or not run_json_after[pim_intf]:
-                found = False
+    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
+    "clear ip/ipv6 pim interfaces" cli
+
+    Parameters
+    ----------
+    * `tgen`: topogen object
+    * `dut`: Device Under Test
+    Usage
+    -----
+
+    result = clear_pim_interfaces(tgen, dut)
+
+    Returns
+    -------
+    errormsg(str) or True
+    """
+
+    logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name))
+
+    nh_before_clear = {}
+    nh_after_clear = {}
+
+    rnode = tgen.routers()[dut]
+
+    logger.info("[DUT: %s]: Verify pim neighbor before pim" " neighbor clear", dut)
+    # To add uptime initially
+    sleep(10)
+    run_json_before = run_frr_cmd(rnode, "show ip pim neighbor json", isjson=True)
+
+    for key, value in run_json_before.items():
+        if bool(value):
+            for _key, _value in value.items():
+                nh_before_clear[key] = _value["upTime"]
+
+    # Clearing PIM neighbors
+    logger.info("[DUT: %s]: Clearing pim interfaces", dut)
+    run_frr_cmd(rnode, "clear ip pim interfaces")
+
+    logger.info("[DUT: %s]: Verify pim neighbor after pim" " neighbor clear", dut)
+
+    found = False
+
+    # Waiting for maximum 60 sec
+    fail_intf = []
+    for retry in range(1, 13):
+        sleep(5)
+        logger.info("[DUT: %s]: Waiting for 5 sec for PIM neighbors" " to come up", dut)
+        run_json_after = run_frr_cmd(rnode, "show ip pim neighbor json", isjson=True)
+        found = True
+        for pim_intf in nh_before_clear.keys():
+            if pim_intf not in run_json_after or not run_json_after[pim_intf]:
+                found = False
                 fail_intf.append(pim_intf)
 
         if found is True:
@@ -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 (file)
index 0000000..e69de29
diff --git a/tests/topotests/multicast_pim6_static_rp_topo1/multicast_pim6_static_rp.json b/tests/topotests/multicast_pim6_static_rp_topo1/multicast_pim6_static_rp.json
new file mode 100644 (file)
index 0000000..9edfae4
--- /dev/null
@@ -0,0 +1,197 @@
+{
+    "address_types": ["ipv6"],
+    "ipv6base": "fd00::",
+    "ipv6mask": 64,
+    "link_ip_start": {
+        "ipv6": "fd00::",
+        "v6mask": 64
+    },
+    "lo_prefix": {
+        "ipv6": "2001:db8:f::",
+        "v6mask": 128
+    },
+    "routers": {
+        "r0": {
+            "links": {
+                "r1": {"ipv6": "auto"}
+            }
+        },
+        "r1": {
+            "links": {
+                "lo": {"ipv6": "auto", "type": "loopback", "pim6": "enable",
+                "ospf6": {
+                    "area": "0.0.0.0",
+                    "hello_interval": 1,
+                    "dead_interval": 4
+                }},
+                "r0": {"ipv6": "auto", "pim6": "enable"},
+                "r2": {"ipv6": "auto", "pim6": "enable",
+                "ospf6": {
+                    "area": "0.0.0.0",
+                    "hello_interval": 1,
+                    "dead_interval": 4
+                }},
+                "r3": {"ipv6": "auto", "pim6": "enable",
+                "ospf6": {
+                    "area": "0.0.0.0",
+                    "hello_interval": 1,
+                    "dead_interval": 4
+                }},
+                "r4": {"ipv6": "auto", "pim6": "enable",
+                "ospf6": {
+                    "area": "0.0.0.0",
+                    "hello_interval": 1,
+                    "dead_interval": 4
+                }}
+            },
+            "ospf6": {
+                "router_id": "100.1.1.0",
+                "neighbors": {
+                    "r2": {},
+                    "r3": {},
+                    "r4": {}
+                },
+                "redistribute": [
+                    {
+                        "redist_type": "static"
+                    },
+                    {
+                        "redist_type": "connected"
+                    }
+                ]
+            },
+            "mld": {
+                "interfaces": {
+                    "r1-r0-eth0" :{
+                        "mld":{
+                        }
+                    }
+                }
+            }
+        },
+        "r2": {
+            "links": {
+                "lo": {"ipv6": "auto", "type": "loopback", "pim6": "enable",
+                "ospf6": {
+                    "area": "0.0.0.0",
+                    "hello_interval": 1,
+                    "dead_interval": 4
+                }},
+                "r1": {"ipv6": "auto", "pim6": "enable",
+                "ospf6": {
+                    "area": "0.0.0.0",
+                    "hello_interval": 1,
+                    "dead_interval": 4
+                }},
+                "r3": {"ipv6": "auto", "pim6": "enable",
+                "ospf6": {
+                    "area": "0.0.0.0",
+                    "hello_interval": 1,
+                    "dead_interval": 4
+                }}
+            },
+            "ospf6": {
+                "router_id": "100.1.1.1",
+                "neighbors": {
+                    "r1": {},
+                    "r3": {}
+                },
+                "redistribute": [
+                    {
+                        "redist_type": "static"
+                    },
+                    {
+                        "redist_type": "connected"
+                    }
+                ]
+            }
+        },
+        "r3": {
+            "links": {
+                "lo": {"ipv6": "auto", "type": "loopback", "pim6": "enable",
+                "ospf6": {
+                    "area": "0.0.0.0",
+                    "hello_interval": 1,
+                    "dead_interval": 4
+                }},
+                "r1": {"ipv6": "auto", "pim6": "enable",
+                "ospf6": {
+                    "area": "0.0.0.0",
+                    "hello_interval": 1,
+                    "dead_interval": 4
+                }},
+                "r2": {"ipv6": "auto", "pim6": "enable",
+                "ospf6": {
+                    "area": "0.0.0.0",
+                    "hello_interval": 1,
+                    "dead_interval": 4
+                }},
+                "r4": {"ipv6": "auto", "pim6": "enable",
+                "ospf6": {
+                    "area": "0.0.0.0",
+                    "hello_interval": 1,
+                    "dead_interval": 4
+                }},
+                "r5": {"ipv6": "auto", "pim6": "enable"}
+            },
+            "ospf6": {
+                "router_id": "100.1.1.2",
+                "neighbors": {
+                    "r1": {},
+                    "r2": {},
+                    "r4": {}
+                },
+                "redistribute": [
+                    {
+                        "redist_type": "static"
+                    },
+                    {
+                        "redist_type": "connected"
+                    }
+                ]
+            }
+        },
+        "r4": {
+            "links": {
+                "lo": {"ipv6": "auto", "type": "loopback", "pim6": "enable",
+                "ospf6": {
+                    "area": "0.0.0.0",
+                    "hello_interval": 1,
+                    "dead_interval": 4
+                }},
+                "r1": {"ipv6": "auto", "pim6": "enable",
+                "ospf6": {
+                    "area": "0.0.0.0",
+                    "hello_interval": 1,
+                    "dead_interval": 4
+                }},
+                "r3": {"ipv6": "auto", "pim6": "enable",
+                "ospf6": {
+                    "area": "0.0.0.0",
+                    "hello_interval": 1,
+                    "dead_interval": 4
+                }}
+            },
+            "ospf6": {
+                "router_id": "100.1.1.3",
+                "neighbors": {
+                    "r1": {},
+                    "r3": {}
+                },
+                "redistribute": [
+                    {
+                        "redist_type": "static"
+                    },
+                    {
+                        "redist_type": "connected"
+                    }
+                ]
+            }
+        },
+        "r5": {
+            "links": {
+                "r3": {"ipv6": "auto"}
+            }
+        }
+    }
+}
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 (executable)
index 0000000..dd8818e
--- /dev/null
@@ -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 (executable)
index 0000000..f366708
--- /dev/null
@@ -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/multicast_pimv6_static_rp.json b/tests/topotests/multicast_pim_static_rp_topo1/multicast_pimv6_static_rp.json
deleted file mode 100644 (file)
index 9edfae4..0000000
+++ /dev/null
@@ -1,197 +0,0 @@
-{
-    "address_types": ["ipv6"],
-    "ipv6base": "fd00::",
-    "ipv6mask": 64,
-    "link_ip_start": {
-        "ipv6": "fd00::",
-        "v6mask": 64
-    },
-    "lo_prefix": {
-        "ipv6": "2001:db8:f::",
-        "v6mask": 128
-    },
-    "routers": {
-        "r0": {
-            "links": {
-                "r1": {"ipv6": "auto"}
-            }
-        },
-        "r1": {
-            "links": {
-                "lo": {"ipv6": "auto", "type": "loopback", "pim6": "enable",
-                "ospf6": {
-                    "area": "0.0.0.0",
-                    "hello_interval": 1,
-                    "dead_interval": 4
-                }},
-                "r0": {"ipv6": "auto", "pim6": "enable"},
-                "r2": {"ipv6": "auto", "pim6": "enable",
-                "ospf6": {
-                    "area": "0.0.0.0",
-                    "hello_interval": 1,
-                    "dead_interval": 4
-                }},
-                "r3": {"ipv6": "auto", "pim6": "enable",
-                "ospf6": {
-                    "area": "0.0.0.0",
-                    "hello_interval": 1,
-                    "dead_interval": 4
-                }},
-                "r4": {"ipv6": "auto", "pim6": "enable",
-                "ospf6": {
-                    "area": "0.0.0.0",
-                    "hello_interval": 1,
-                    "dead_interval": 4
-                }}
-            },
-            "ospf6": {
-                "router_id": "100.1.1.0",
-                "neighbors": {
-                    "r2": {},
-                    "r3": {},
-                    "r4": {}
-                },
-                "redistribute": [
-                    {
-                        "redist_type": "static"
-                    },
-                    {
-                        "redist_type": "connected"
-                    }
-                ]
-            },
-            "mld": {
-                "interfaces": {
-                    "r1-r0-eth0" :{
-                        "mld":{
-                        }
-                    }
-                }
-            }
-        },
-        "r2": {
-            "links": {
-                "lo": {"ipv6": "auto", "type": "loopback", "pim6": "enable",
-                "ospf6": {
-                    "area": "0.0.0.0",
-                    "hello_interval": 1,
-                    "dead_interval": 4
-                }},
-                "r1": {"ipv6": "auto", "pim6": "enable",
-                "ospf6": {
-                    "area": "0.0.0.0",
-                    "hello_interval": 1,
-                    "dead_interval": 4
-                }},
-                "r3": {"ipv6": "auto", "pim6": "enable",
-                "ospf6": {
-                    "area": "0.0.0.0",
-                    "hello_interval": 1,
-                    "dead_interval": 4
-                }}
-            },
-            "ospf6": {
-                "router_id": "100.1.1.1",
-                "neighbors": {
-                    "r1": {},
-                    "r3": {}
-                },
-                "redistribute": [
-                    {
-                        "redist_type": "static"
-                    },
-                    {
-                        "redist_type": "connected"
-                    }
-                ]
-            }
-        },
-        "r3": {
-            "links": {
-                "lo": {"ipv6": "auto", "type": "loopback", "pim6": "enable",
-                "ospf6": {
-                    "area": "0.0.0.0",
-                    "hello_interval": 1,
-                    "dead_interval": 4
-                }},
-                "r1": {"ipv6": "auto", "pim6": "enable",
-                "ospf6": {
-                    "area": "0.0.0.0",
-                    "hello_interval": 1,
-                    "dead_interval": 4
-                }},
-                "r2": {"ipv6": "auto", "pim6": "enable",
-                "ospf6": {
-                    "area": "0.0.0.0",
-                    "hello_interval": 1,
-                    "dead_interval": 4
-                }},
-                "r4": {"ipv6": "auto", "pim6": "enable",
-                "ospf6": {
-                    "area": "0.0.0.0",
-                    "hello_interval": 1,
-                    "dead_interval": 4
-                }},
-                "r5": {"ipv6": "auto", "pim6": "enable"}
-            },
-            "ospf6": {
-                "router_id": "100.1.1.2",
-                "neighbors": {
-                    "r1": {},
-                    "r2": {},
-                    "r4": {}
-                },
-                "redistribute": [
-                    {
-                        "redist_type": "static"
-                    },
-                    {
-                        "redist_type": "connected"
-                    }
-                ]
-            }
-        },
-        "r4": {
-            "links": {
-                "lo": {"ipv6": "auto", "type": "loopback", "pim6": "enable",
-                "ospf6": {
-                    "area": "0.0.0.0",
-                    "hello_interval": 1,
-                    "dead_interval": 4
-                }},
-                "r1": {"ipv6": "auto", "pim6": "enable",
-                "ospf6": {
-                    "area": "0.0.0.0",
-                    "hello_interval": 1,
-                    "dead_interval": 4
-                }},
-                "r3": {"ipv6": "auto", "pim6": "enable",
-                "ospf6": {
-                    "area": "0.0.0.0",
-                    "hello_interval": 1,
-                    "dead_interval": 4
-                }}
-            },
-            "ospf6": {
-                "router_id": "100.1.1.3",
-                "neighbors": {
-                    "r1": {},
-                    "r3": {}
-                },
-                "redistribute": [
-                    {
-                        "redist_type": "static"
-                    },
-                    {
-                        "redist_type": "connected"
-                    }
-                ]
-            }
-        },
-        "r5": {
-            "links": {
-                "r3": {"ipv6": "auto"}
-            }
-        }
-    }
-}
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 (executable)
index bd5473a..0000000
+++ /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))
index 3b84a99cdfe13fd4fe0286cc8fa6f75671bf67ae..e131fba0c350cb9017b5fedfbd28538d758ce1d7 100644 (file)
@@ -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))
index 7c5dc3ffe06d85cfaf9b3b4c2cd94a70e1cb7799..c47789a1663387624c004796211817d3ef643dc6 100644 (file)
@@ -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
index 69e10191f3e8b94b1a40163d59b043ba0bb5b811..a9771f70ca02ac0a107db6d1b922915b39f398f3 100644 (file)
@@ -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
index d6bfca63f0f325f78c49776df5b33d2a142acb72..18aee4ffabace0e1d5b57073309a0d2fb1dbe1a7 100644 (file)
           "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,
         "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
             }
           ]
         }
         "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
             }
           ]
         }
         "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
             }
           ]
         }
           "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
             }
           ]
         }
         "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
             }
           ]
         }
         "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
             }
           ]
         },
           "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,
         "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,
index ec30af60350ff16ba7a3cd52933404de469be344..1ed7272560f8b87e2dd1b07135c74baad639f039 100644 (file)
           "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,
         "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
             }
           ]
         }
           "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
             }
           ]
         }
         "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
             }
           ]
         }
         "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
             }
           ]
         },
           "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,
         "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,
index 853704b4f610c00d144e1f815fd3e0830fe6f018..0e79670c78f6cd94ece12136b66b15397d258bd2 100644 (file)
           "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,
         "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
             }
           ]
         }
           "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
             }
           ]
         }
         "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
             }
           ]
         }
         "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
             }
           ]
         },
           "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,
index 0aa57713c0b0a5ae7ea901b061bef04377924332..860dcb3f216a6ce9a0a0d176228e3017c4482aec 100644 (file)
           "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,
         "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
             }
           ]
         },
           "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
             }
           ]
         }
         "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
             }
           ]
         },
         "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
             }
           ]
         },
           "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,
index 07637f3048cc93e71f52f9ed03ae1a7bc5acae20..615a691c451660b15b83cc7fc2a3064763b7195d 100644 (file)
           "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,
         "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
             }
           ]
         },
         "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
             }
           ]
         },
         "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
             }
           ]
         },
           "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
             }
           ]
         }
         "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
             }
           ]
         },
         "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
             }
           ]
         },
           "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,
index e9eee96ff40c3d67f31875b1c151d31cfe0a1f00..3b84d258081fb967dc9f745154c83df3e9d09cb1 100644 (file)
           "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,
         "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
             }
           ]
         },
         "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
             }
           ]
         },
         "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
             }
           ]
         },
           "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
             }
           ]
         }
         "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
             }
           ]
         },
         "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,
           "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
index f912ae4a876da9813175de4d71555c791c402de1..83f8a1d5d60f3cb2c90d9db04648f4279e80be10 100644 (file)
           "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,
         "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
             }
           ]
         },
         "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
             }
           ]
         },
         "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
             }
           ]
         },
           "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
             }
           ]
         }
         "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
             }
           ]
         },
index 631c8025b57ccf948f6a99cdaffb611c6bbfe30f..94c8c5c732faa6f2b7bb9da57e31d70e4dc30b77 100644 (file)
@@ -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()
index 7dd13935b1e4931817ad98a3a78562b5759a8c53..6986e3051c954b20c723d60c29c346a3f19d885a 100644 (file)
@@ -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 (file)
index 0000000..e69de29
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 (file)
index 0000000..fe51488
--- /dev/null
@@ -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 (file)
index 0000000..9f34c58
--- /dev/null
@@ -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 (file)
index 0000000..fe51488
--- /dev/null
@@ -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 (file)
index 0000000..0d4f101
--- /dev/null
@@ -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 (file)
index 0000000..0d4f101
--- /dev/null
@@ -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 (file)
index 0000000..0d4f101
--- /dev/null
@@ -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 (file)
index 0000000..e89a56a
--- /dev/null
@@ -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 (file)
index 0000000..f2ca09a
--- /dev/null
@@ -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 (file)
index 0000000..e89a56a
--- /dev/null
@@ -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 (file)
index 0000000..4c75d7f
--- /dev/null
@@ -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 (file)
index 0000000..a01d313
--- /dev/null
@@ -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 (file)
index 0000000..6e1b993
--- /dev/null
@@ -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 (file)
index 0000000..36ed713
--- /dev/null
@@ -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 (file)
index 0000000..d460859
--- /dev/null
@@ -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 (file)
index 0000000..30a520b
--- /dev/null
@@ -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 (executable)
index 0000000..ecc0856
--- /dev/null
@@ -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 (file)
index 0000000..e69de29
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 (file)
index 0000000..fe51488
--- /dev/null
@@ -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 (file)
index 0000000..304d738
--- /dev/null
@@ -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 (file)
index 0000000..fe51488
--- /dev/null
@@ -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 (file)
index 0000000..fe51488
--- /dev/null
@@ -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 (file)
index 0000000..0d4f101
--- /dev/null
@@ -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 (file)
index 0000000..0d4f101
--- /dev/null
@@ -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 (file)
index 0000000..0d4f101
--- /dev/null
@@ -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 (file)
index 0000000..0d4f101
--- /dev/null
@@ -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 (file)
index 0000000..c0eeacc
--- /dev/null
@@ -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 (file)
index 0000000..38a6739
--- /dev/null
@@ -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 (file)
index 0000000..c0eeacc
--- /dev/null
@@ -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 (file)
index 0000000..b1528ff
--- /dev/null
@@ -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 (file)
index 0000000..b6acc23
--- /dev/null
@@ -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 (file)
index 0000000..b1528ff
--- /dev/null
@@ -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 (file)
index 0000000..e965e02
--- /dev/null
@@ -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 (file)
index 0000000..6e1b993
--- /dev/null
@@ -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 (file)
index 0000000..36ed713
--- /dev/null
@@ -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 (file)
index 0000000..d460859
--- /dev/null
@@ -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 (file)
index 0000000..78ef1e9
--- /dev/null
@@ -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 (executable)
index 0000000..37fd736
--- /dev/null
@@ -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))
index 4cb1c4ae13311ece15c929a4f9bf1a71152186a8..e39192256607f45859c22f5bc76bf0debe288ef1 100644 (file)
             "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"
   }
 ]
index 691adb0a1966a87e422d7e7c3b12d92396e7951e..ec27ec95b8425fb10387c020df8fdb0f0cd5482d 100644 (file)
@@ -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
index d9cca5cd93320f2a14150d3d29f8ea8fde197feb..66d3b6d9172d7be81e3080c19ed1d3531fd86f5d 100755 (executable)
@@ -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
index ff2c633ccc6156c85914c8d22d9fb58e813a9239..914363157a1da29fb1db3b7025127ddc7e567306 100644 (file)
@@ -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/tools/etc/logrotate.d/frr b/tools/etc/logrotate.d/frr
new file mode 100644 (file)
index 0000000..735af65
--- /dev/null
@@ -0,0 +1,27 @@
+/var/log/frr/*.log {
+        size 500k
+        sharedscripts
+        missingok
+        compress
+        rotate 14
+        create 0640 frr frr
+
+        postrotate
+            pid=$(lsof -t -a -c /syslog/ /var/log/frr/* 2>/dev/null)
+            if [ -n "$pid" ]
+            then # using syslog
+                 kill -HUP $pid
+            fi
+            # in case using file logging; if switching back and forth
+            # between file and syslog, rsyslogd might still have file
+            # open, as well as the daemons, so always signal the daemons.
+            # It's safe, a NOP if (only) syslog is being used.
+            for i in babeld bgpd eigrpd isisd ldpd nhrpd ospf6d ospfd sharpd \
+                pimd pim6d ripd ripngd zebra pathd pbrd staticd bfdd fabricd vrrpd; do
+                if [ -e /var/run/frr/$i.pid ] ; then
+                    pids="$pids $(cat /var/run/frr/$i.pid)"
+                fi
+            done
+            [ -n "$pids" ] && kill -USR1 $pids || true
+        endscript
+}
index 32f9a7884197ef5710afbfd34bbe956a18d84220..7c5d91d4dc5471a722eee8a0ec77cac75a3f24d8 100755 (executable)
@@ -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")
index 27b2c0ab84d8a83b47fe97969ec17226024ba802..1ffdade54f21126891adc9721868a9f8c311b064 100755 (executable)
@@ -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 $?
                ;;
 
index b589ced965aec46e89728b46adaa98ee335cb6af..3c16c27c6dfa135b54f3ab7e25969b32726edc5d 100755 (executable)
@@ -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."
index ee10b89e52abc6559012dfebb490ac38f7704018..2396b1a3260f2a443edc5e9d9d2d1adfec9308f0 100644 (file)
@@ -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 $?
        ;;
 
index b280cc15b105748b015571a6fdb6036e100fbe65..a0b041f2f2fbd88e030db22871bfb102c4742407 100644 (file)
@@ -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, " ");
index 02e0497eef13869602e48b98003ad0de2535b261..03b404261197d1edddcac80a875fb36b874e8479 100644 (file)
@@ -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
index 634a55dbc37fd3390b6375df0d67a579311a3496..f822b89854ab8e1bd0290050d89ebc13a31121a3 100644 (file)
@@ -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;
 }
 
index 118b84407beb97816bf9fe85dc05e7e841b9a95b..09e90e51d2edcb820a478d1eed9c12015b226ecd 100644 (file)
@@ -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 (executable)
index 228a136..0000000
+++ /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
index 624361645e66ae80e078ccb88ceaa38f6894fab9..cc2a70ade63619114fe1be39c8af372735be9ca8 100644 (file)
@@ -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
index f39ecf0709014e248efde9fb6f034d4a371ee7e7..48274d717018e6743ebfd5b8595d3b8c4d1b502d 100644 (file)
@@ -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"
index d98f83dbf6d6f32482a1ca2b0caf2de9d661087b..ac0cdc6ffd3d06ef6d947e002bdeef72ece5a845 100644 (file)
@@ -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");
index e899b895e7c50f6c84c6e6025b1a0c024c535609..04a4aaf166bd9dd35e92e6996a85f037ddc58e79 100644 (file)
@@ -4,7 +4,6 @@
 
 if WATCHFRR
 sbin_PROGRAMS += watchfrr/watchfrr
-vtysh_scan += watchfrr/watchfrr_vty.c
 man8 += $(MANBUILD)/frr-watchfrr.8
 endif
 
index 423f25faa2ccb8652681935b9aab0a16fe67c2cb..4a3575ae75051b6719e5f65bf3b25dfbe2b3e822 100644 (file)
@@ -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();
index 1492ee37b600073b443cf3d2aea8eba5e39657a2..742b474eab6f8ebc25c38fc6aac926b4130b7d2b 100644 (file)
@@ -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,
index 3f3d8292117c5ae00bdc513f9b6023b93291e783..ad2a142fef6d180310a924304f13c5a8b0c946b2 100644 (file)
@@ -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 {
index 0812c86facf65da3b5ad313be8f8201cc0ac2592..380fce385990bb02f2358d1ac67a4702f78f1545 100644 (file)
@@ -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 {
index 69aaed33acb5a88ed5640c804334e4e6ab2b204f..16aac7909fa9771ca8887d356c89ccaf6da40539 100644 (file)
@@ -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;
 }
 
index 748bce9e3456098d11314902fa8389385a7a13e0..d1814af3b7d8e4ea1d5cad794433b01a55d00850 100644 (file)
@@ -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"
index d07c4c63324b9985acd4725e097cdd20677dbf96..c5e1c113cb0844e0e2bb90dbbaa599eb87e6959f 100644 (file)
@@ -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);
index c674b499ac82ad6ec4e30506300262ab653630ec..32703b59bc764d4e2b82afccc2cf80675576d0e2 100644 (file)
@@ -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);
 
index 46cf2eea7dea60871397daa1b3d49e7c4be806a1..3de97943fd1629581098c6cbef32f9b830a94fe7 100644 (file)
@@ -229,6 +229,7 @@ void zebra_finalize(struct thread *dummy)
 
        zebra_router_terminate();
 
+       ns_terminate();
        frr_fini();
        exit(0);
 }
index 56f56bfe669d2df7d89855fe56ec5a5acf463021..4c30544e5df472d4f33dd9767024ba98a276ac39 100644 (file)
@@ -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);
index 99f52bcd4e434070c3ea20ddad4a1a39645df2c7..166500fa5cc7d829b03432cd6e94503db1567f2d 100644 (file)
@@ -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;
index e883033d59c61297a94ed2307dce7452a73cd1fd..2396dfe4d69fed937c1ca8e3676d3a054c613272 100644 (file)
@@ -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)
index 127888d6554796f2ee5674784a21c11a0f67ab22..a8ec60844cdaf5fc340caf3053cc79474caba17a 100644 (file)
@@ -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");
index 298b71598c4b96b0ac3a230d8b17126d60759c67..9842931496d41b31eaf945e50a8ba4a4ece54441 100644 (file)
@@ -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
index 4fb0241d1d47d45ed7a51589b9a280a048f08ab0..afa03a4fa5689c922a62e904f6e55d32d95b70da 100644 (file)
@@ -25,7 +25,7 @@
 
 #ifdef HAVE_NETLINK
 
-#include <linux/if_ether.h>
+#include <netinet/if_ether.h>
 #include <sys/socket.h>
 
 #include "if.h"
index 761ba789b87afb1ab3193956ec67432477444a6a..130fb972db70b7819c6063ba3a1339eb2cb025d0 100644 (file)
@@ -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);
index 043ea0f248e63f8f1a1266801918e55d8384c789..01ea9c5b9c924d4af15dba0bd64f9247ad3cf2e6 100644 (file)
@@ -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);
 }
index 1b2753377b1dac792aa4c4a3e6f30c490a630a0f..f9f4ee476df553d6502acb7c59679b813ca2b403 100644 (file)
@@ -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))
index ebaaf03dabc8d8bf37cdf913bd4a5a6a1b716873..a1c544d5d84827a486c1c603d8e6c19a2a683b9a 100644 (file)
@@ -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,
index 1964c763c579ad6e51c3bceebc0e51239c6f52b7..5fadd4c82ba279587a6e2c6ecc0651d9cad9dcda 100644 (file)
@@ -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;
 
index 62f71f943fddd17a2ef9dc30df6de88f1538e3ff..9b925bf10fd7dc8dede4733864a3c96a3086609a 100644 (file)
@@ -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);
 
index fceaaaa9f02633a1dd24433841dc22bdb962a1e0..54ef4768ebe8c0472a64205a8799271a8469634a 100644 (file)
@@ -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
index 2cc84a1f7fcbb6710cf6432e9da5948fc6aba229..13d1995d58943be4c685e3951b696bdb9b6a0b3d 100644 (file)
@@ -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;
index c0f18dd09160085ddbeced7a34a8e17d46d14c5c..7d95607fcf3ba1f57950561aeae4e60c17ce2364 100644 (file)
@@ -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);
 }
index fe77809446d095c81e864c34e1e18f543c32922b..dff2f595fd3a822c3723bcded5964e09998dbbd7 100644 (file)
@@ -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,
index 36506cacc7b33a406ef791d0fbb45ee55c652e25..d61e4f8045d9493f8ca2ed78f057c25cab8a4f91 100644 (file)
@@ -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;
index 84fcc305bc3264049e506f4f30ece2e2b13ce298..f320b9ca0f94e3c514b64b602ad2af028118483e 100644 (file)
@@ -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);
index 62ce17326c240dbf4937d051dee627300c0232be..1221365d4d5e5e826c3afa2afda9ca7cc97bf8cd 100644 (file)
@@ -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);
index 42d6aefa9ac01bd145611458fcd1d9d33577ad8b..2f8b5048d5948016f784a285be6f2e8519f71d27 100644 (file)
 #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 */
index a2844ca9568f69fb775083c6d36a204ffc8bf4c6..c99aa2e8ffff88a1c8226b0828bd063d13a79bb2 100644 (file)
@@ -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,
index 77922d2fc4db3af860a905802e3c2a1d9614a32d..6561ac95fa3d81808f41eeb0a997010bedeae59c 100644 (file)
@@ -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)